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 organise the group chat & chat 1 on 1

It gives examples of how to:

  1. Organize chat between 2 users
  2. Organize group chat

Setup

Android Studio IDE

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

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.

Login to 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

// Initialise Chat service
QBChatService chatService = QBChatService.getInstance();
 
final QBUser user = new QBUser("garrysantos", "garrysantospass");
QBAuth.createSession(user, new QBEntityCallback<QBSession>() {
    @Override
    public void onSuccess(QBSession session, Bundle params) {
        // success, login to chat
 
        user.setId(session.getUserId());
 
        chatService.login(qbUser, new QBEntityCallback() {
            @Override
            public void onSuccess() {
 
            }
 
            @Override
            public void onError(QBResponseException errors) {
 
            }
        });
    }
 
    @Override
    public void onError(QBResponseException errors) {
 
    }
});

To handle different connection states use ConnectionListener:

ConnectionListener connectionListener = new ConnectionListener() {
    @Override
    public void connected(XMPPConnection connection) {
 
    }
 
    @Override
    public void authenticated(XMPPConnection connection) {
 
    }
 
    @Override
    public void connectionClosed() {
 
    }
 
    @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);


Chat in background mode

Android provides 'true' background mode but the better way to handle correctly chat offline messages is to do 'Chat logout' when app goes to background and does 'Chat login' when app goes to foreground.

Logout from Chat

Next code does chat logout:

boolean isLoggedIn = chatService.isLoggedIn();
if(!isLoggedIn){
    return;
}
 
chatService.logout(new QBEntityCallback() {
 
    @Override
    public void onSuccess() {
        // success
 
        chatService.destroy();
    }
 
    @Override
    public void onError(QBResponseException errors) {
 
    }
});

Reconnection

By default Android SDK reconnects automatically when connection to server is lost.

But there is a way to disable this and then manage this manually:

QBChatService.getInstance().setReconnectionAllowed(false);

Dialogs

QuickBlox provides a way to organise a chat dialogs page where you can show all user's current chat dialogs.

Dialogs can have next types:

  • 1-1 private dialog - a chat dialog between 2 users
  • Group dialog - a chat dialog between many users
  • Open group dialog - open chat dialog, any user can join and chat here.

Retrieve list of dialogs

Here is how typical screen with all your chats looks like:

Chat2 dialogs android.png

Request Dialogs each time user logins to app:

QBRequestGetBuilder requestBuilder = new QBRequestGetBuilder();
requestBuilder.setLimit(100);
 
QBChatService.getChatDialogs(null, requestBuilder, new QBEntityCallback<ArrayList<QBDialog>>() {
    @Override
    public void onSuccess(ArrayList<QBDialog> dialogs, Bundle args) {
        int totalEntries = args.getInt("total_entries");
    }
 
    @Override
    public void onError(QBResponseException errors) {
 
    }
});

Filters

There are some filters to get only chat dialogs you need, not just all.


You can apply filters for the following fields:

  • _id (string)
  • type (integer)
  • name (string)
  • last_message_date_sent (integer)
  • created_at (date)
  • updated_at (date)

You can apply sort for the following fields:

  • last_message_date_sent


Filters:

Operator Description Usage example
{field_name} Search records with field which contains exactly specified value requestBuilder.addRule("type", QueryRule.EQ, "2");
{field_name}[{search_operator}] Search record with field which contains value according to specified value and operator.

Possible filters: lt (Less Than operator), lte (Less Than or Equal to operator), gt (Greater Than operator), gte (Greater Than or Equal to operator), ne (Not Equal to operator), in (Contained IN array operator), nin (Not contained IN array), all (ALL contained IN array), ctn (Contains substring operator)
requestBuilder.in("type", "1", "2");
limit Limit search results to N records. Useful for pagination. Default value - 100 requestBuilder.setLimit(100);
skip Skip N records in search results. Useful for pagination. Default (if not specified): 0 requestBuilder.setSkip(50);
sort_desc/sort_asc Search results will be sorted by specified field in ascending/descending order requestBuilder.sortAsc("last_message_

date_sent");

To use filters, you should build a QBRequestGetBuilder request and pass it to 'get dialogs' request above:

QBRequestGetBuilder requestBuilder = new QBRequestGetBuilder();
requestBuilder.setLimit(100);
requestBuilder.setSkip(5);
requestBuilder.sortAsc("last_message_date_sent");
requestBuilder.gt("updated_at", "1455098137");

Create new dialog

According to REST API, Create a dialog query, you don't need to create a dialog for 1-1(private) chat - it will be created automatically with 1st chat message. But you can create it anyway if you need this for your application.

Create new group chat dialog

When user would like to start a group chat - he must create a group chat dialog first.

Chat2 new dialog android.png

User should choose other users to add them to a new group dialog. Also he should choose a name for new group chat:

ArrayList<Integer> occupantIdsList = new ArrayList<Integer>();
occupantIdsList.add(34);
occupantIdsList.add(17);
 
QBDialog dialog = new QBDialog();
dialog.setName("Chat with Garry and John");
dialog.setPhoto("1786");
dialog.setType(QBDialogType.GROUP);
dialog.setOccupantsIds(occupantIdsList);
 
QBGroupChatManager groupChatManager = QBChatService.getInstance().getGroupChatManager();
groupChatManager.createDialog(dialog, new QBEntityCallback<QBDialog>() {
    @Override
    public void onSuccess(QBDialog dialog, Bundle args) {
 
    }
 
    @Override
    public void onError(QBResponseException errors) {
 
    }
});

To notify all occupants that the group chat was created we use chat notifications - it's simple chat message with extra parameters inside. These parameters used to separate chat notifications from regular text chat messages:

public static QBChatMessage createChatNotificationForGroupChatCreation(QBDialog dialog) {
    String dialogId = String.valueOf(dialog.getDialogId());
    String roomJid = dialog.getRoomJid();
    String occupantsIds = TextUtils.join(",", dialog.getOccupants());
    String dialogName = dialog.getName();
    String dialogTypeCode = String.valueOf(dialog.getType().ordinal());
 
    QBChatMessage chatMessage = new QBChatMessage();
    chatMessage.setBody("optional text");
 
    // Add notification_type=1 to extra params when you created a group chat 
    //
    chatMessage.setProperty("notification_type", "1");
 
    chatMessage.setProperty("_id", dialogId);
    if (!TextUtils.isEmpty(roomJid)) {
        chatMessage.setProperty("room_jid", roomJid);
    }
    chatMessage.setProperty("occupants_ids", occupantsIds);
    if (!TextUtils.isEmpty(dialogName)) {
        chatMessage.setProperty("name", dialogName);
    }
    chatMessage.setProperty("type", dialogTypeCode);
 
    return chatMessage;
}
 
...
 
QBSystemMessagesManager systemMessagesManager = QBChatService.getInstance().getSystemMessagesManager();
 
for (Integer userID : dialog.getOccupants()) {
 
    QBChatMessage chatMessage = createChatNotificationForGroupChatCreation(dialog);
 
    long time = DateUtils.getCurrentTime();
    chatMessage.setProperty("date_sent", time + "");
 
    chatMessage.setRecipientId(userID);
 
    try {
        systemMessagesManager.sendSystemMessage(chatMessage);
    } catch (SmackException.NotConnectedException e) {
 
    } catch (IllegalStateException ee){
 
    }
}
 
...
 
QBSystemMessageListener systemMessageListener = new QBSystemMessageListener() {
    @Override
    public void processMessage(QBChatMessage qbChatMessage) {
 
    }
 
    @Override
    public void processError(QBChatException e, QBChatMessage qbChatMessage) {
 
    }
};
systemMessagesManager.addSystemMessageListener(systemMessageListener);


Set dialog's avatar

The Chat dialog contains a field photo. It's a string field, can contain any value:


For example, we use Content module to store the dialog's photo. Next snippets show how to upload a file to Content module and set it as a photo of a dialog:

File filePhoto = new File("dialog_avatar.png");
Boolean fileIsPublic = false;
QBContent.uploadFileTask(filePhoto, fileIsPublic, null, new QBEntityCallback<QBFile>() {
    @Override
    public void onSuccess(QBFile file, Bundle params) {        
        dialog.setPhoto(file.getId().toString);
    }
 
    @Override
    public void onError(QBResponseException errors) {
        // error
    }
});

Create new 1-1(private) chat dialog

If you would like to create a private chat dialog too - use next snippets:

QBPrivateChatManager privateChatManager = QBChatService.getInstance().getPrivateChatManager();
privateChatManager.createDialog(opponentId, new QBEntityCallback<QBDialog>() {
    @Override
    public void onSuccess(QBDialog dialog, Bundle args) {
 
    }
 
    @Override
    public void onError(QBResponseException errors) {
 
    }
});

Custom parameters

Dialogs can store additional parameters. These parameters can be used to store an additional data. Also these parameters can be used in dialogs retrieval requests.

To start use additional parameters it needs to create an additional schema of your parameters. This is a CustomObjects class. Just create an empty class with all needed fields. These fields will be your dialog additional parameters.

When you create a dialog then set a dialog's field customData:

QBDialogCustomData data = new QBDialogCustomData("Advert"); // class name
data.putString("title", "Magic Beans"); // field 'title'
data.putInteger("advert_id", 5665); // field 'advert_id'
newDialog.setCustomData(data);

It's also possible to use custom parameters in a dialogs retrieval requests so dialogs can be filtered through custom parameters:

QBRequestGetBuilder requestBuilder = new QBRequestGetBuilder();
requestBuilder.addRule("data[class_name]", QueryRule.EQ, "Advert");
requestBuilder.addRule("data[title]", QueryRule.EQ, "bingo");

Update group dialog

User can update group chat dialog name, add new occupants or leave this group chat. To add more occupants use push operator. To leave group chat (remove yourself) - use pull all operator:

Chat2 update dialog android.png


QBRequestUpdateBuilder requestBuilder = new QBRequestUpdateBuilder();
requestBuilder.push("occupants_ids", 378); // add another users
// requestBuilder.pullAll("occupants_ids", 22); // Remove yourself (user with ID 22)
 
QBGroupChatManager groupChatManager = QBChatService.getInstance().getGroupChatManager();
groupChatManager.updateDialog("53aac645535c12bd3b008a40", "Team room", requestBuilder, new QBEntityCallback<QBDialog>() {
    @Override
    public void onSuccess(QBDialog dialog, Bundle args) {
 
    }
 
    @Override
    public void onError(QBResponseException errors) {
 
    }
});

To notify all occupants that you updated a group chat we use chat notifications - it's simple chat message with extra parameters inside. These parameters used to separate chat notifications from regular text chat messages:

public static QBChatMessage createChatNotificationForGroupChatUpdate(QBDialog dialog) {
    String dialogId = String.valueOf(dialog.getDialogId());
    String roomJid = dialog.getRoomJid();
    String occupantsIds = TextUtils.join(",", dialog.getOccupants());
    String dialogName = dialog.getName();
    String dialogTypeCode = String.valueOf(dialog.getType().ordinal());
 
    QBChatMessage chatMessage = new QBChatMessage();
    chatMessage.setBody("optional text");
 
    // Add notification_type=2 to extra params when you updated a group chat 
    //
    chatMessage.setProperty("notification_type", "2");
 
    chatMessage.setProperty("_id", dialogId);
    if (!TextUtils.isEmpty(roomJid)) {
        chatMessage.setProperty("room_jid", roomJid);
    }
    chatMessage.setProperty("occupants_ids", occupantsIds);
    if (!TextUtils.isEmpty(dialogName)) {
        chatMessage.setProperty("name", dialogName);
    }
    chatMessage.setProperty("type", dialogTypeCode);
 
    return chatMessage;
}
 
...
 
QBSystemMessagesManager systemMessagesManager = QBChatService.getInstance().getSystemMessagesManager();
 
for (Integer userID : dialog.getOccupants()) {
 
    QBChatMessage chatMessage = createChatNotificationForGroupChatUpdate(dialog);
 
    long time = DateUtils.getCurrentTime();
    chatMessage.setProperty("date_sent", time + "");
 
    chatMessage.setRecipientId(userID);
 
    try {
        systemMessagesManager.sendSystemMessage(chatMessage);
    } catch (SmackException.NotConnectedException e) {
 
    } catch (IllegalStateException ee){
 
    }
}
 
...
 
QBSystemMessageListener systemMessageListener = new QBSystemMessageListener() {
    @Override
    public void processMessage(QBChatMessage qbChatMessage) {
 
    }
 
    @Override
    public void processError(QBChatException e, QBChatMessage qbChatMessage) {
 
    }
};
systemMessagesManager.addSystemMessageListener(systemMessageListener);

Delete dialog

To delete a dialog use next snippet:

QBGroupChatManager groupChatManager = QBChatService.getInstance().getGroupChatManager();
groupChatManager.deleteDialog(dialogID, new QBEntityCallback<Void>() {
    @Override
    public void onSuccess() {
 
    }
 
    @Override
    public void onError(QBResponseException errors) {
 
    }
});

This request will remove this dialog for current user, but other users still will be able to chat there.

Chat in dialog

Chat in 1-1 private dialog

To send a message in 1-1 chat - choose opponent's user ID and create a body of chat message.

QBMessageListener<QBPrivateChat> privateChatMessageListener = new QBMessageListener<QBPrivateChat>() {
    @Override
    public void processMessage(QBPrivateChat privateChat, final QBChatMessage chatMessage) {
 
    }
 
    @Override
    public void processError(QBPrivateChat privateChat, QBChatException error, QBChatMessage originMessage){
 
    }
};
 
QBPrivateChatManagerListener privateChatManagerListener = new QBPrivateChatManagerListener() {
    @Override
    public void chatCreated(final QBPrivateChat privateChat, final boolean createdLocally) {
        if(!createdLocally){
            privateChat.addMessageListener(privateChatMessageListener);
        }
    }
};
QBChatService.getInstance().getPrivateChatManager().addPrivateChatManagerListener(privateChatManagerListener);
 
Integer opponentId = 45;
 
try {
    QBChatMessage chatMessage = new QBChatMessage();
    chatMessage.setBody("Hi there!");
    chatMessage.setProperty("save_to_history", "1"); // Save a message to history
 
    QBPrivateChat privateChat = privateChatManager.getChat(opponentId);
    if (privateChat == null) {
        privateChat = privateChatManager.createChat(opponentId, privateChatMessageListener);
    }
    privateChat.sendMessage(chatMessage);
} catch (XMPPException e) {
 
} catch (SmackException.NotConnectedException e) {
 
}

Chat in group dialog

Before start chatting in a group dialog, you should join this dialog.

QBMessageListener<QBGroupChat> groupChatQBMessageListener = new QBMessageListener<QBGroupChat>() {
    @Override
    public void processMessage(final QBGroupChat groupChat, final QBChatMessage chatMessage) {
 
    }
 
    @Override
    public void processError(final QBGroupChat groupChat, QBChatException error, QBChatMessage originMessage){
 
    }
};
 
QBDialog groupDialog = ...;
 
DiscussionHistory history = new DiscussionHistory();
history.setMaxStanzas(0);
 
QBGroupChatManager groupChatManager = QBChatService.getInstance().getGroupChatManager();
 
QBGroupChat currentChatRoom = groupChatManager.createGroupChat(groupDialog.getRoomJid());
currentChatRoom.join(history, new QBEntityCallback() {
    @Override
    public void onSuccess() {
        // add listeners
        currentChatRoom.addMessageListener(groupChatQBMessageListener);
    }
 
    @Override
    public void onError(QBResponseException errors) {
 
    }
});


Now you can send and receive messages:

QBChatMessage chatMessage = new QBChatMessage();
chatMessage.setBody("Hi there");
chatMessage.setProperty("save_to_history", "1"); // Save to Chat 2.0 history
 
try {
    currentChatRoom.sendMessage(chatMessage);
} catch (XMPPException e) {
 
} catch (SmackException.NotConnectedException e) {
 
} catch (IllegalStateException e){
 
}
Get online users

You can request online users in group chat dialog

Collection<Integer> onlineGroupUsers = null;
try {
    onlineRoomUsers = currentChatRoom.getOnlineUsers();
} catch (XMPPException e) {
 
}

And you also can handle online users in real time:

private QBParticipantListener participantListener;
 
participantListener = new QBParticipantListener() {
    @Override
    public void processPresence(QBGroupChat groupChat, QBPresence presence) {
 
    }
};
 
private QBGroupChat currentChatRoom = ...;
currentChatRoom.addParticipantListener(participantListener);
Leave group chat dialog
try {
    currentChatRoom.leave();
    currentChatRoom = null;
} catch (XMPPException e) {
 
} catch (SmackException.NotConnectedException e) {
 
}

Send and receive a message with attachment

Send attachment

It's possible to add attachments to message: for example, image, audio file or video file. We don't have any restrictions here - you can attach any type of file.

To send a message with attachments you should use the same way as you send regular message with text, but add to it an attachment object. Attachment can be:


To send a message with attachment you have to upload a file to Content module, Custom Objects module using sample above or use an url to any file in Internet. Then you should incorporate an ID to file to message.

For example, we use Content module to store attachments. Next snippets show how to upload a file to Content module and send it as an attach:

File filePhoto = new File("holy_grail.png");
Boolean fileIsPublic = false;
QBContent.uploadFileTask(filePhoto, fileIsPublic, null, new QBEntityCallback<QBFile>() {
    @Override
    public void onSuccess(QBFile file, Bundle params) {
 
        // create a message
        QBChatMessage chatMessage = new QBChatMessage();
        chatMessage.setProperty("save_to_history", "1"); // Save a message to history
 
        // attach a photo
        QBAttachment attachment = new QBAttachment("photo");
        attachment.setId(file.getId().toString());
        chatMessage.addAttachment(attachment);
 
        // send a message
        // ...
    }
 
    @Override
    public void onError(QBResponseException errors) {
        // error
    }
});

Receive attachment

For example we use Content module to store attachments. Next snippets allow to receive a message with an attachment and download it:

// QBMessageListener
 
...
 
@Override
public void processMessage(QBPrivateChat privateChat, final QBChatMessage chatMessage) {
    for(QBAttachment attachment : chatMessage.getAttachments()){
        Integer fileId = attachment.getId();
 
        // download a file
        QBContent.downloadFileTask(fileId, new QBEntityCallback<InputStream>(){
            @Override
            public void onSuccess(InputStream inputStream, Bundle params) {
                // process file
            }
 
            @Override
            public void onError(QBResponseException errors) {
                // errors
            }
        });
    }
}
 
...

Use custom parameters in a message

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:

QBChatMessage chatMessage = new QBChatMessage();
chatMessage.setBody("Hi there");
 
chatMessage.setProperty("name", "Bob");
chatMessage.setProperty("age", "25");

Unread messages count

You can request total unread messages count or unread count for particular dialog:

Set<String> dialogsIds = new HashSet<String>() {{
    add("56f3fac3a0eb4786ae00003f"); add("56f3f546a28f9affc0000033");
}};
 
QBChatService.getTotalUnreadMessagesCount(dialogsIds, new QBEntityCallback<Integer>() {
    @Override
    public void onSuccess(Integer total, Bundle params) {
        Log.i(TAG, "total unread messages: " + total);
        Log.i(TAG, "dialog Unread1: " + params.getInt("56f3fac3a0eb4786ae00003f"));
        Log.i(TAG, "dialog Unread2: " + params.getInt("56f3f546a28f9affc0000033"));
    }
 
    @Override
    public void onError(QBResponseException responseException) {
    }
});


Chat history

You can choose a way to save chat message to history or not. If you decided to store - you should add save_to_history parameter to message:

QBChatMessage chatMessage = new QBChatMessage();
chatMessage.setProperty("save_to_history", "1");
...


List chat messages

If you decided to use save_to_history parameter - all chat messages will be stored to history and user can request a chat history for particular dialog.

Chat2 messages android.png

To get a chat history for particular dialog use next request:

QBDialog qbDialog = new QBDialog("53cfc593efa3573ebd000017");
 
QBRequestGetBuilder requestBuilder = new QBRequestGetBuilder();
requestBuilder.setLimit(100);
 
QBChatService.getDialogMessages(qbDialog, customObjectRequestBuilder, new QBEntityCallback<ArrayList<QBChatMessage>>() {
    @Override
    public void onSuccess(ArrayList<QBChatMessage> messages, Bundle args) {
 
    }
 
    @Override
    public void onError(QBResponseException errors) {
 
    }
});

Filters

There are some filters to get only chat messages you need, not just all.


You can apply filters for the following fields:

  • _id (string)
  • message (string)
  • date_sent (timestamp)
  • sender_id (integer)
  • recipient_id (integer)
  • attachments.type (string)
  • updated_at (date)

You can apply sort for the following fields:

  • date_sent


Filters:

Operator Description Usage example
{field_name} Search records with field which contains exactly specified value requestBuilder.addRule("type", QueryRule.EQ, "2");
{field_name}[{search_operator}] Search record with field which contains value according to specified value and operator.

Possible filters: lt (Less Than operator), lte (Less Than or Equal to operator), gt (Greater Than operator), gte (Greater Than or Equal to operator), ne (Not Equal to operator), in (Contained IN array operator), nin (Not contained IN array), all (ALL contained IN array), or (OR operator), ctn (Contains substring operator)
requestBuilder.in("type", "1", "2");
limit Limit search results to N records. Useful for pagination. Default value - 100 requestBuilder.setLimit(100);
skip Skip N records in search results. Useful for pagination. Default (if not specified): 0 requestBuilder.setSkip(50);
sort_desc/sort_asc Search results will be sorted by specified field in ascending/descending order requestBuilder.sortAsc("last_message_

date_sent");


To use filters, you should build a QBRequestGetBuilder request and pass it to 'get messages' request above:

QBRequestGetBuilder requestBuilder = new QBRequestGetBuilder();
requestBuilder.setLimit(100);
requestBuilder.setSkip(5);
requestBuilder.sortAsc("date_sent");
requestBuilder.gt("updated_at", "1455098137");

Delete chat messages

To delete chat messages use next snippets:

Set<String> messagesIds = new HashSet<String>() {{
    add("546cc8040eda8f2dd7ee449c"); add("546cc80f0eda8f2dd7ee449d");
}};
 
QBChatService.deleteMessages(messagesIds, new QBEntityCallback<Void>() {
    @Override
    public void onSuccess() {
 
    }
 
    @Override
    public void onError(QBResponseException errors) {
 
    }
});

This request will remove chat messages for current user, but other users still will be able to request them.

Put chat messages to history

It's also possible to create/send chat message via REST request:

QBChatMessage msg = new QBChatMessage();
msg.setBody("hello worls");
 
msg.setRecipientId(223);
// msg.setDialogId("546cc8040eda8f2dd7ee449c"); Set the dialog Id or recipient Id
 
QBAttachment attachment = new QBAttachment("photo");
attachment.setId("3451");
msg.addAttachment(attachment);
 
msg.setProperty("param1", "value1");
msg.setProperty("param2", "value2");
 
QBChatService.createMessage(msg, new QBEntityCallback<QBChatMessage>() {
    @Override
    public void onSuccess(QBChatMessage result, Bundle params) {
 
    }
 
    @Override
    public void onError(QBResponseException errors) {
 
    }
});

This request will put a message into history without actually sending it.

To send this message use property send_to_chat:

msg.setProperty("send_to_chat", "1");


Push notifications to the offline users

QuickBlox provides a way to setup automatic push notifications for the offline users. It means if your opponent is offline while you sending a message - he will automatically receive push notification.

Read how to setup automatic push notifications in Admin panel in Alerts section.


Dashboard

QuickBlox dashboard provide a way to view and manage all dialogs for your application. Go to admin panel, Chat module. Read more info here.


Contact list

Contact list mode

In traditional IM applications, the "buddy" system is rather straightforward. User A sends a request to become "friends" with user B. User B accepts the friend request. And now user A and B appear in each other's roster.


But, alternatively, you can use twitter like logic. User A sends a presence subscription request to user B. Think about this more like following on twitter. User A is requesting permission to receive presence information from user B (following their presence). User B can accept this request, but may not be interested in receiving presence info from user B. Again, this is more like twitter following, but with the addition of required permission.So when user B accepts the request, this *only* means that user A will receive presence from user B. It does *not* mean that user B will receive presence from user A. Again, twitter-style, user A is now "following" user B. In diagram form, presence is flowing like this:

 A <-- B


Now, if B also wants to receive presence from user A, then user B must request this permission. And furthermore, user A must accept the request. Just because B has granted A permission to receive presence, doesn't mean that B gets a free pass to receive presence from A.


By default this SDK provides 'twitter like' mode.

To enable Facebook like logic pass QBRoster.SubscriptionMode.mutual value when you are obtaining a roser:

QBRoster chatRoster = QBChatService.getInstance().getRoster(QBRoster.SubscriptionMode.mutual, subscriptionListener);

Access to the Contact list

Main setup

To access contact list you have to obtain it and set all needed listeners:

QBRosterListener rosterListener = new QBRosterListener() {
    @Override
    public void entriesDeleted(Collection<Integer> userIds) {
 
    }
 
    @Override
    public void entriesAdded(Collection<Integer> userIds) {
 
    }
 
    @Override
    public void entriesUpdated(Collection<Integer> userIds) {
 
    }
 
    @Override
    public void presenceChanged(QBPresence presence) {
 
    }
};
 
QBSubscriptionListener subscriptionListener = new QBSubscriptionListener() {
    @Override
    public void subscriptionRequested(int userId) {
 
    }
};
 
 
// Do this after success Chat login
QBRoster chatRoster = QBChatService.getInstance().getRoster(QBRoster.SubscriptionMode.mutual, subscriptionListener);
chatRoster.addRosterListener(rosterListener);

QBRosterListener is a listener that is fired any time a roster is changed or the presence of a user in the roster is changed (user becomes online/offline)

QBSubscriptionListener is a listener that is fired on "subscribe" (add to contact list) request from any user.

Access contact list users

To get users from contact list:

Collection<QBRosterEntry> entries = сhatRoster.getEntries();

QBRosterEntry describes a user entity in your contact list. To get user's ID use getUserId() getter.

To request user's status (online/offline):

int userID = 45;
 
QBPresence presence = chatRoster.getPresence(userID);
if (presence == null) {
    // No user in your roster
    return;
}
 
if (presence.getType() == QBPresence.Type.online) {
    // User is online
}else{
    // User is offline
}

Add/Remove users

To add users to the contact list just use the method below:

int userID = 56;
 
if (chatRoster.contains(userID)) {
    try {
        chatRoster.subscribe(userID);
    } catch (SmackException.NotConnectedException e) {
 
    }
} else {
    try {
        chatRoster.createEntry(userID, null);
    } catch (XMPPException e) {
 
    } catch (SmackException.NotLoggedInException e) {
 
    } catch (SmackException.NotConnectedException e) {
 
    } catch (SmackException.NoResponseException e) {
 
    }
}

This user will receive the request to be added to the contact list

// QBSubscriptionListener
 
...
 
@Override
public void subscriptionRequested(int userId) {
 
}

To confirm the request:

try {
    chatRoster.confirmSubscription(userID);
} catch (SmackException.NotConnectedException e) {
 
} catch (SmackException.NotLoggedInException e) {
 
} catch (XMPPException e) {
 
} catch (SmackException.NoResponseException e) {
 
}

To reject the request:

try {
    chatRoster.reject(userID);
} catch (SmackException.NotConnectedException e) {
 
}

To remove a previously added user from the contact list:

int userID = 67;
 
try {
    chatRoster.unsubscribe(userID);
} catch (SmackException.NotConnectedException e) {
 
}

Custom status

A client MAY provide detailed status information to his contacts by constructing a presence object by himself:

QBPresence presence = new QBPresence(QBPresence.Type.online, "I'm at home", 1, QBPresence.Mode.available);
try {
    chatRoster.sendPresence(presence);
} catch (SmackException.NotConnectedException e) {
 
}

In this case there is no need to use QBChatService.getInstance().startAutoSendPresence(60);, you have to manage it by yourself.

Privacy lists

Privacy list API allows to enable or disable communication with other users in a chat. Privacy list API also enables a user to create, modify, or delete his privacy lists, define a default list.

Retrieve privacy lists

User can have multiple privacy lists. To get a list of all your privacy lists' use next request:

QBPrivacyListsManager privacyListsManager = QBChatService.getInstance().getPrivacyListsManager()        
privacyListsManager.addPrivacyListListener(privacyListListener);
 
// get privacy lists' names
List<QBPrivacyList> lists = null;
try {
    lists = privacyListsManager.getPrivacyLists();
} catch (SmackException.NotConnectedException e) {
    e.printStackTrace();
} catch (XMPPException.XMPPErrorException e) {
    e.printStackTrace();
} catch (SmackException.NoResponseException e) {
    e.printStackTrace();
}

Create a privacy list or edit existing list

A privacy list must have at least one element in order to create it. If no elements specified then the list with given name will be deleted. When you want to update a privacy list, it must include all of the desired items (i.e., not a "delta").

QBPrivacyList list = new QBPrivacyList();
list.setName("public");
 
ArrayList<QBPrivacyListItem> items = new ArrayList<QBPrivacyListItem>();
 
QBPrivacyListItem item1 = new QBPrivacyListItem();
item1.setAllow(false);
item1.setType(QBPrivacyListItem.Type.USER_ID);
item1.setValueForType(String.valueOf(3678));
 
items.add(item1);
 
list.setItems(items);
 
try {
    privacyListsManager.setPrivacyList(list);
} catch (SmackException.NotConnectedException e) {
    e.printStackTrace();
} catch (XMPPException.XMPPErrorException e) {
    e.printStackTrace();
} catch (SmackException.NoResponseException e) {
    e.printStackTrace();
}
 
// set listener
QBPrivacyListListener privacyListListener = new QBPrivacyListListener() {
    @Override
    public void setPrivacyList(String listName, List<QBPrivacyListItem> listItem){
 
    }
 
    @Override
    public void updatedPrivacyList(String listName) {
 
    }
};

QBPrivacyListItem class takes 3 arguments:

  • type - use USER_ID block a user in 1-1 chat or GROUP_USER_ID to block in a group chat.
  • valueForType - ID of a user to apply an action
  • allow - can be true/false.

Activate a privacy list

User can have multiple privacy lists, but active can be only one. In order to activate rules from a privacy list you must activate it by setting as default.

"Active" makes a list active for current chat session and "Default" makes it active for all further sessions so you don't need to activate it every time.

try {
    privacyListsManager.setPrivacyListAsDefault("public");
    privacyListsManager.setPrivacyListAsActive("public");
} catch (SmackException.NotConnectedException e) {
    e.printStackTrace();
} catch (XMPPException.XMPPErrorException e) {
    e.printStackTrace();
} catch (SmackException.NoResponseException e) {
    e.printStackTrace();
}

Retrieve a privacy list

QBPrivacyList list = null;
try {
    list = privacyListsManager.getPrivacyList("public");
} catch (SmackException.NotConnectedException e) {
    e.printStackTrace();
} catch (XMPPException.XMPPErrorException e) {
    e.printStackTrace();
} catch (SmackException.NoResponseException e) {
    e.printStackTrace();
}

Delete existing privacy list

try {
    privacyListsManager.deletePrivacyList("public");
} catch (SmackException.NotConnectedException e) {
    e.printStackTrace();
} catch (XMPPException.XMPPErrorException e) {
    e.printStackTrace();
} catch (SmackException.NoResponseException e) {
    e.printStackTrace();
}

Blocked user attempts to communicate with user

Blocked entities will be receiving an error when try to chat with a user in a 1-1 chat and will be receiving nothing in a group chat:

QBChatMessage chatMessage = new QBChatMessage();
chatMessage.setBody("Hey man!");
 
QBPrivateChat privateChat = privateChatManager.getChat(1876);
if (privateChat == null) {
    privateChat = privateChatManager.createChat(1876, privateChatMessageListener);
}
privateChat.sendMessage(chatMessage);
 
...
 
QBMessageListener<QBPrivateChat> privateChatMessageListener = new QBMessageListener<QBPrivateChat>() {
    @Override
    public void processMessage(QBPrivateChat privateChat, final QBChatMessage chatMessage) {
 
    }
 
    @Override
    public void processError(QBPrivateChat privateChat, QBChatException error, QBChatMessage originMessage){
        log("processError: " + error.getLocalizedMessage());
    }
};
Log output:
processError: Service not available.


Typing status

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. typing: 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)


With QuickBlox you can use all these chat status notifications.

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

int opponentId = 45;
QBPrivateChat privateChat = privateChatManager.getChat(opponentId);
if (privateChat == null) {
    privateChat = privateChatManager.createChat(opponentId, privateChatMessageListener);
}
 
try {
    privateChat.sendIsTypingNotification();
} catch (XMPPException e) {
 
} catch (SmackException.NotConnectedException e) {
 
}

Also it's possible to send a stop typing notification:

try {
    privateChat.sendStopTypingNotification();
} catch (XMPPException e) {
 
} catch (SmackException.NotConnectedException e) {
 
}

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

QBIsTypingListener<QBPrivateChat> privateChatIsTypingListener = new QBIsTypingListener<QBPrivateChat>() {
    @Override
    public void processUserIsTyping(QBPrivateChat privateChat, Integer userId) {
 
    }
 
    @Override
    public void processUserStopTyping(QBPrivateChat privateChat, Integer userId) {
 
    }
};
 
privateChat.addIsTypingListener(privateChatIsTypingListener);

The same also possible for QBGroupChat.

Sent status

Starting from Android SDK 2.5 you can track the 'sent' status of your message. It means that your message has been delivered to the server.

To start using the feature you should enable Stream Management first.

Pay attention: you should enable Stream Management before logging into the chat. Stream Management is initialized only during login step.

QBChatService chatService = QBChatService.getInstance();
 
chatService.setUseStreamManagement(true);
chatService.login(currentUser);

The Stream Management defines an extension for active management of a stream between client and server, including features for stanza acknowledgements.

Next - you can attach the QBMessageSentListener listener to your chat and track the status:

private QBMessageSentListener<QBPrivateChat> privateChatMessageSentListener = new QBMessageSentListener<QBPrivateChat>() {
    @Override
    public void processMessageSent(QBPrivateChat qbChat, QBChatMessage qbChatMessage) {
 
    }
 
    @Override
    public void processMessageFailed(QBPrivateChat qbChat, QBChatMessage qbChatMessage) {
 
    }
};
 
QBPrivateChat privateChat = ...;
privateChat.addMessageSentListener(privateChatMessageSentListener);

The same can be done for group chats.

Delivered status

SDK automatically manages delivery notifications for all 'online' messages if you use marked messages.

Term 'marked' relies to messages that have automatic delivery control.

To mark a message as 'markable' use next message property:

QBChatMessage chatMessage = new QBChatMessage();
chatMessage.setMarkable(true);
...

For such messages you will receive delivery confirmation:

private QBMessageStatusesManager messageStatusesManager;
private QBMessageStatusListener messageStatusListener;
 
// call it after chat login
messageStatusesManager = QBChatService.getInstance().getMessageStatusesManager();
 
messageStatusListener = new QBMessageStatusListener() {
    @Override
    public void processMessageDelivered(String messageId, String dialogId, Integer userId) {
 
    }
 
    @Override
    public void processMessageRead(String messageId, String dialogId, Integer userId) {
 
    }
};
 
messageStatusesManager.addMessageStatusListener(messageStatusListener);

It is also possible to send a 'delivered' status manually, for example for messages received via REST API:

QBChatMessage message = ...;
 
try {
    privateChat.deliverMessage(message);
    // group.deliverMessage(message);
} catch (XMPPException e) {
 
} catch (SmackException.NotConnectedException e) {
 
}


Read status

You can manage 'read' notifications in chat. For example, User1 sends messages to User2 and User1 would like to know when User2 reads these messages.

First of all, if User1 would like to handle 'read' status of his messages, he should mark message as markable. To mark a message as 'markable' use chatMessage.setMarkable(true) class method to create a message instance.


User1 sends a message:

Integer opponentId = 45;
try {
    QBChatMessage chatMessage = new QBChatMessage();
    chatMessage.setBody("Hi there!");
    chatMessage.setProperty("save_to_history", "1"); // Save a message to history
    chatMessage.setMarkable(true);
 
    QBPrivateChat privateChat = privateChatManager.getChat(opponentId);
    if (privateChat == null) {
        privateChat = privateChatManager.createChat(opponentId, privateChatMessageListener);
    }
    privateChat.sendMessage(chatMessage);
 
    // save packet ID of current message
    String _id = chatMessage.getId();
} catch (XMPPException e) {
 
} catch (SmackException.NotConnectedException e) {
 
}

User2 receives a message, reads it and sends 'read' status back:

// QBMessageListener
 
...
 
@Override
public void processMessage(QBPrivateChat privateChat, final QBChatMessage chatMessage) {
    if(chatMessage.isMarkable()){
        try {
            privateChat.readMessage(chatMessage);
        } catch (XMPPException e) {
 
        } catch (SmackException.NotConnectedException e) {
 
        }
    }
}

User1 receives a 'read' status notification that User2 read his message:

private QBMessageStatusesManager messageStatusesManager;
private QBMessageStatusListener messageStatusListener;
 
// call it after chat login
messageStatusesManager = QBChatService.getInstance().getMessageStatusesManager();
 
messageStatusListener = new QBMessageStatusListener() {
    @Override
    public void processMessageDelivered(String messageId, String dialogId, Integer userId) {
 
    }
 
    @Override
    public void processMessageRead(String messageId, String dialogId, Integer userId) {
 
    }
};
 
messageStatusesManager.addMessageStatusListener(messageStatusListener);


Message carbons

This feature defines an approach for ensuring that all of user's devices get both sides of all conversations in order to avoid confusion. Information about the current state of a conversation is shared between all of a user's clients that enable this feature.

Is it convenient to enable carbons after chat login:

try {
    QBChatService.getInstance().enableCarbons();
 
    // QBChatService.getInstance().disableCarbons();
} catch (XMPPException e) {
 
} catch (SmackException e) {
 
}

For example, a user is online on 2 devices, phone and pad. On his phone he sends a message to other user:

Integer opponentId = 45;
 
try {
    QBChatMessage chatMessage = new QBChatMessage();
    chatMessage.setBody("Hi there!");
    chatMessage.setProperty("save_to_history", "1"); // Save a message to history
 
    QBPrivateChat privateChat = privateChatManager.getChat(opponentId);
    if (privateChat == null) {
        privateChat = privateChatManager.createChat(opponentId, privateChatMessageListener);
    }
    privateChat.sendMessage(chatMessage);
} catch (XMPPException e) {
 
} catch (SmackException.NotConnectedException e) {
 
}

In this moment he also receives the message on his pad device:

privateChatMessageListener = new QBMessageListener<QBPrivateChat>() {
    @Override
    public void processMessage(QBPrivateChat privateChat, final QBChatMessage chatMessage) {
 
        if(chatMessage.getSenderId().equals(chatService.getUser().getId())){
            // Message comes here from carbons
        }
    }
 
    @Override
    public void processError(QBPrivateChat privateChat, QBChatException error, QBChatMessage originMessage){
 
    }
};


Mobile optimisations

In default configuration messages and other chat packets are sent to client when processing is finished, but in mobile environment sending or receiving data drains battery due to use of radio.

To save energy data should be sent to client only if it is important or client is waiting for it.

When mobile client is entering inactive it is possible to notify the backend about this:

try {
    QBChatService.getInstance().enterInactiveState();
} catch (SmackException.NotConnectedException e) {
 
}

After receiving packets server starts queueing packets which should be send to mobile client. Only last presence from each source is kept in queue, also Message Carbons are queued. Any other packets (such as iq or plain message) is sent immediately to the client.

When mobile client is entering active it is possible to notify the backend about this:

try {
    QBChatService.getInstance().enterActiveState();
} catch (SmackException.NotConnectedException e) {
 
}

After receiving this server sends all queued packets to the client. Also all packets from queue will be sent if number of packets in queue will reach queue size limit - limit is set to 50.


System notifications

There is a way to send system notifications to other users about some events. These messages work over separated channel and won't be mixed with the regular chat messages:

private QBSystemMessagesManager systemMessagesManager;
private QBSystemMessageListener systemMessageListener;
 
systemMessagesManager = QBChatService.getInstance().getSystemMessagesManager();
systemMessageListener = new QBSystemMessageListener() {
    @Override
    public void processMessage(QBChatMessage qbChatMessage) {
 
    }
 
    @Override
    public void processError(QBChatException e, QBChatMessage qbChatMessage) {
 
    }
};
systemMessagesManager.addSystemMessageListener(systemMessageListener);
 
...
 
try {
    QBChatMessage chatMessage = new QBChatMessage();
    chatMessage.setProperty("param1", "value1");
    chatMessage.setProperty("param2", "value2");
 
    chatMessage.setRecipientId(18);
 
    systemMessagesManager.sendSystemMessage(chatMessage);
 
} catch (SmackException.NotConnectedException e) {
 
} catch (IllegalStateException ee){
 
}

Ping manager

The Ping manager allows a user to ping the backend by simply sending a ping to it. This is useful in a case to check a connection between user and server.

final QBPingManager pingManager = QBChatService.getInstance().getPingManager();
pingManager.pingServer(new QBEntityCallback<Void>() {
 
    @Override
    public void onSuccess() {
 
    }
 
    @Override
    public void onError(QBResponseException error) {
 
    }
});
 
// or sync version
final QBPingManager pingManager = QBChatService.getInstance().getPingManager();
try {
    boolean pingSuccess = pingManager.pingServer();
} catch (SmackException.NotConnectedException e) {
    e.printStackTrace();
}

PingManger also periodically sends XMPP pings to the server every 30 minutes to avoid NAT timeouts and to test the connection status. To configure the ping interval and to listen for fails:

QBChatService.getInstance().setPingInterval(30);
 
pingManager.addPingFailedListener(new PingFailedListener(){
    public void pingFailed(){
 
    }
});

Ping a user

It's also possible to ping some user to check whethere he is online or not:

final QBPingManager pingManager = QBChatService.getInstance().getPingManager();
int userId = 56456;
pingManager.pingUser(userId, new QBEntityCallback<Void>() {
    @Override
    public void onSuccess(Void result, Bundle params) {
 
    }
 
    @Override
    public void onError(QBResponseException e) {
 
    }
});
 
// or sync version
try {
    boolean pingUser = pingManager.pingUser(userId);
} catch (SmackException.NotConnectedException e) {
 
}

Stickers

This sample also demonstrates how to add stickers to your chat (full sample on https://github.com/908Inc/stickerpipe-chat-sample)

Dependencies

Add stickers repository in build.gradle:

repositories {
   maven { url  'http://maven.stickerpipe.com/artifactory/stickerfactory' }
}

Add library dependency in build.gradle:

compile('vc908.stickers:stickerfactory:x.x.x@aar') {
     transitive = true;
}

List of available versions you can find here http://maven.stickerpipe.com/artifactory/stickerfactory/vc908/stickers/stickerfactory/

Eclipse IDE

Use this guide https://github.com/908Inc/stickerpipe-android-sdk-for-eclipse to add StickerPipe library in Eclipse.

Manifest

Add content provider with your application package to your manifest file:

<provider
     android:name="vc908.stickerfactory.provider.StickersProvider"
     android:authorities="<YOUR PACKAGE>.stickersProvider"
     android:exported="false"/>

Initialization

Initialize library at your Application onCreate() method

StickersManager.initialize(“847b82c49db21ecec88c510e377b452c", this);

You can get your own API Key on http://stickerpipe.com to have customized packs set.

Stickers fragment and customisation

Create stickers fragment

stickersFragment = new StickersFragment.Builder().build();

You can customize stickers fragment with next setters:

  • setOnStickerSelectedListener

Set sticker selected listener It’s highly recommended to set listener outside of builder, directly to fragment when creating or restoring activity.

  • setStickerPlaceholderDrawableRes

Set custom placeholder for stickers in list

  • setStickerPlaceholderColorFilterRes

Set color filter for sticker’s placeholder

  • setStickersListBackgroundDrawableRes

Set background drawable resource for stickers list with Shader.TileMode.REPEAT

  • setStickersListBackgroundColorRes

Set stickers list background color

  • setTabPlaceholderDrawableRes

Set custom placeholder for tab icons

  • setTabBackgroungColorRes

Set tab panal background color

  • setTabUnderlineColorRes

Set selected tab underline color

  • setTabIconsFilterColorRes

Set color filter for default tab icons placeholder

  • setMaxStickerWidth

Set max width for sticker cell

  • setBackspaceFilterColorRes

Set color filter for backspace button at emoji tab

  • setEmptyRecentTextRes

Set text for empty view at recent tab

  • setEmptyRecentTextColorRes

Set text color for empty view at recent tab

  • setEmptyRecentImageRes

Set image for empty view at recent tab

  • setEmptyRecentColorFilterRes

Set image color filter for empty view at recent tab

Then you only need to show fragment.

Stickers showing and customizations

To send stickers you need to set listener and handle results

// create listener
private OnStickerSelectedListener stickerSelectedListener = new OnStickerSelectedListener() {
    @Override
    public void onStickerSelected(String code) {
        if (StickersManager.isSticker(code)) {
	    // send message
        } else {
            // append emoji to your edittext
        }
    }
};
// set listener to your stickers fragment
stickersFragment.setOnStickerSelectedListener(stickerSelectedListener)

Listener can take an emoji, so you need to check code first, and then send sticker code or append emoji to your edittext.

// Show sticker in adapter
if (StickersManager.isSticker(message)){ // check your chat message
StickersManager.with(context) // your context - activity, fragment, etc
        .loadSticker(message)
          .into((imageView)); // your image view 
} else {
	// show a message as it is
}

And you can customize sticker loading process with next setters:

  • setPlaceholderDrawableRes

Set sticker placeholder drawable

  • setPlaceholderColorFilterRes

Set color filter for default placeholder