Chat Android v4
Chat Android
Chat
Android
Home
/
Chat
/
Android
/
Group channel
This is the new Docs for Chat SDK v4 beta for Android. To see the previous Docs, click here.

Group channel: Advanced

This page explains the advanced features for group channels.


Send typing indicators to other members

If the startTyping() and endTyping() methods are called while the current user is typing a text message in a group channel, onTypingStatusUpdated() in the channel event handler will be invoked on all channel members' devices except the one that belongs to the current user.

groupChannel.startTyping();
groupChannel.endTyping();
...

// To listen to an update from all the other channel members' client apps, implement the onTypingStatusUpdated() with things to do when notified.
SendbirdChat.addChannelHandler(
    UNIQUE_HANDLER_ID,
    object : GroupChannelHandler() {
        override fun onTypingStatusUpdated(channel: GroupChannel) {
            if (currentGroupChannel.url == channel.url) {
                val members = channel.typingUsers

                // Refresh typing status of members within the channel.
                ...
            }
        }
    }
)

Mark messages as delivered

To mark messages as delivered when a group channel member receives a push notification for the message from FCM, either the SendbirdChat.markAsDelivered() static method.

class FirebaseMessagingServiceEx : FirebaseMessagingService() {
    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        SendbirdChat.markAsDelivered(remoteMessage.data)
    }
}

When a message is delivered to an online group channel member, it is automatically marked as delivered and the other online members are notified of delivery receipt through the onDeliveryStatusUpdated() handler in the channel event handler.

SendbirdChat.addChannelHandler(
    UNIQUE_HANDLER_ID,
    object : GroupChannelHandler() {
        override fun onMessageReceived(channel: BaseChannel, message: BaseMessage) {
            ...
        }

        override fun onDeliveryStatusUpdated(channel: GroupChannel) {
            ...
        }
    }
)

Mark messages as read

To keep the most up-to-date and accurate read status of messages for all group channel members, the markAsRead() method should be called every time one of the members reads messages by entering the channel from a channel list or bringing the opened channel view to the foreground.

If the current user opens a channel and the markAsReadAll() method is called, Sendbird server will update both the unread message count of the individual channel and the total unread message count of all the group channels joined by the user. The server then notifies the change of read status to all members' devices through the onReadStatusUpdated() method in the channel event handler, except the one that is being used by the current user.

Note : When a channel member sends a message to the channel, Sendbird server updates the member's read receipt to the time when the message has sent. Meanwhile, the read receipts of other channel members can be updated when the markAsRead() method is called. If a new member joins the channel, the method works differently based on the value of the display_past_message property of your Sendbird application. If the property is set to true, the new member’s read receipt will be updated to the sent time of the last message in the channel. If false, it will be updated to 0.

// Call the 'markAsRead()' when the current user views unread messages in a group channel.
groupChannel.markAsRead(null)
...

// To listen to an update from all the other channel members' client apps, implement the onReadStatusUpdated() with things to do when notified.
SendbirdChat.addChannelHandler(
    UNIQUE_HANDLER_ID,
    object : GroupChannelHandler() {
        override fun onMessageReceived(channel: BaseChannel, message: BaseMessage) {}

        override fun onReadStatusUpdated(channel: GroupChannel) {
            if (currentGroupChannel.url == channel.url) {
                // For example, code for redrawing a channel view.
            }

            ...
        }
    }
)

Note: The display_past_message property determines whether to display past messages to newly joined members when they enter the channel. This property is also linked to the Chat history option, which can be adjusted in your dashboard under Settings > Chat > Channels > Group channels.


Retrieve number of members who haven't received a message

You can retrieve the number of members who haven’t received a specific message in a group channel. If zero is returned, it means that the message has been delivered to all the other members.

SendbirdChat.addChannelHandler(
    UNIQUE_HANDLER_ID,
    object : GroupChannelHandler() {
        override fun onMessageReceived(channel: BaseChannel, message: BaseMessage) {
            ...
        }

        override fun onDeliveryStatusUpdated(channel: GroupChannel) {
            val isAllDelivered = channel.getUndeliveredMemberCount(message) == 0
        }
    }
)

Retrieve members who have read a message

Using the getReadMembers() method, you can view members who have read a specific message in a group channel. The method returns a list of channel members who have read the message by comparing the message’s creation time and the channel members’ read receipt. The list will exclude the current user and the message sender.

Note: Read receipt indicates the timestamp of the latest time when each user has read messages in the channel in Unix milliseconds.

If you want to keep track of who has read a new message, we recommend that you use the getReadMembers() method in the onReadStatusUpdated(). Then the client app will receive a callback from Sendbird server whenever a channel member reads a message. To do so, you should pass the new message object as an argument to a parameter in the getReadMembers() method through the onReadStatusUpdated() handler.

val readMembers = groupChannel.getReadMembers(message, false)

Note: Using the getUnreadMembers() method, you can also view members who have not read a specific message in a group channel, except the current user and the message sender. In the meantime, you can get information on each channel member's read receipt through the getReadStatus() method.


Retrieve number of members who haven't read a message

Using the getUnreadMemberCount() method, you can get the number of members who haven't read a specific message in a group channel. To get the exact value, the channel should be updated first through the markAsRead() before calling the getUnreadMemberCount() method.

// Call the markAsRead() when the current user views unread messages in a group channel.
groupChannel.markAsRead(null)
...

// To listen to an update from all the other channel members' client apps, implement the onReadReceiptUpdated() with things to do when notified.
SendbirdChat.addChannelHandler(
    UNIQUE_HANDLER_ID,
    object : GroupChannelHandler() {
        override fun onReadStatusUpdated(channel: GroupChannel) {
            if (currentGroupChannel.url == channel.url) {
                messages.forEach { message ->
                    val unreadCount = channel.getUnreadMemberCount(message)
                    if (unreadCount <= 0) {
                        // All members have read the message.
                    } else {
                        // Some of members haven't read the message yet.
                    }
                }
            }
        }
    }
)

Retrieve the last message of a channel

You can view the last message of a group channel.

val lastMessage = groupChannel.lastMessage

Retrieve number of unread messages in a channel

You can retrieve the total number of the current user's unread messages in a group channel.

val unreadMessageCount = groupChannel.unreadMessageCount

Retrieve number of unread messages in all channels

You can retrieve the total number of the current user's unread messages in all joined group channels.

SendbirdChat.getTotalUnreadMessageCount { totalUnreadCount, e ->
    if (e != null) {
        // Handle error.
    }

    ...
}

Retrieve number of channels with unread messages

You can retrieve the total number of the current user's joined group channels with one or more unread messages.

SendbirdChat.getTotalUnreadChannelCount { totalUnreadChannelCount, e ->
    if (e != null) {
        // Handle error.
    }

    ...
}

Send an admin message

You can send admin messages to a group channel using Sendbird Dashboard or Chat Platform API. To send an admin message through your dashboard, go to the Chat > Group channels, select a group channel, find the message box below, click the Admin message tab, and then write your message in the box. An admin message is limited to 1,000 characters.

Unlike other types of messages, a push notification for an admin message isn't available by default. If you want assistance on this, contact our sales team.


Add extra data to a message

You have the option to create further actions in a channel by using extra data in a message. You can add one or more key-values items to a message which you can save, update, or remove, when necessary. Based on those items, you can design and implement several different actions such as measuring user engagement within a chosen time limit through polls or counting how many times a message has been copied by members.

Note: For the quality of performance, every Sendbird application has its own limits to how many key-values items you can add to a single message, as well as the maximum number of values an item can have. If you would like more information on these limits, contact our sales team.

// When a message has been successfully sent to a channel, create items with keys.
val itemKeysToCreate = listOf("referees", "games")
groupChannel.createMessageMetaArrayKeys(message, itemKeysToCreate) { message, e ->
    if (e != null) {
        // Handle error.
    }

    ...
}

// Adding values to specific items by their keys.
val valuesToAdd = mapOf(
    "referees" to listOf("John", "Brandon", "Harry", "Jay"),
    "games" to listOf("soccer", "baseball", "basketball")
)
groupChannel.addMessageMetaArrayValues(message, valuesToAdd) { message, e ->
    if (e != null) {
        // Handle error.
    }

    ...
}

// Removing existing values of specific items by their keys.
val valuesToRemove = mapOf("referees" to listOf("Brandon", "Jay"))
groupChannel.removeMessageMetaArrayValues(message, valuesToRemove) { message, e ->
    if (e != null) {
        // Handle error.
    }

    ...
}

// Deleting items by their keys.
val keysToDelete = listOf("referees", "games")
groupChannel.deleteMessageMetaArrayKeys(message, keysToDelete) { message, e ->
    if (e != null) {
        // Handle error.
    }

    ...
}

To get the key-values items of a message, use the getMetaArrays() method.


Display Open Graph tags in a message

The Chat SDK supports the URL link preview when a message text contains the URL of a web page.

Note: This feature is turned on by default for Sendbird applications. If this isn't available for your Sendbird application, contact our support team to enable the feature.

OGMetaData

OGMetaData is a class that holds the Open Graph (OG) protocol-related data, including the four properties: title, URL, description, and image of an OG object.

Note: Some websites don’t provide the OG metadata fields mentioned above. In that case, even though the Open Graph protocol states them as requirements, all of the four getter methods may return null.

List of methods

MethodDescription

title

Returns the title of the OG object as it should appear within the graph. The value can be null.

url

Returns the canonical URL of the object that can be used as its permanent ID in the graph. The value can be null.

description

Returns the description of the object. The value can be null.

ogImage

Returns an OGImage object that contains information about the image that this Open Graph points to. The OGImage also holds its own properties such as type, URL, and size. However, the value can be null.

OGImage

OGImage is a class that holds image-related data for an OGMetaData object. The OGImage class can also have six optional structured properties of URL, secure URL, type, width, height, and alt.

Note: Except for width and height, other fields such as URL, secure URL, type, and alt can be null. Width and height are set to 0 if the target website doesn’t provide such data.

List of methods

MethodDescription

url

Returns the URL of an image object within the Open Graph. The value can be null.

secureUrl

Returns an alternative url to use if the webpage requires HTTPS. The value can be null.

type

Returns a media type or MIME type of this image. The value can be null.

width

Returns the number of pixels horizontal. When the value is unavailable, this method returns 0.

height

Returns the number of pixels vertical. When the value is unavailable, this method returns 0.

alt

Returns a description of what is in the image, not a caption of the image. The alt attribute is designed to provide a fuller context of the OGImage object and help users better understand it when they can’t load or see the image. The value can be null.

How it works

If a user sends a message with a web page URL and the linked web page possesses Open Graph (OG) tags, or OG metadata, Sendbird server parses the message content, extracts the URL in the message, gets the OG metadata from it, and creates an OG metadata object for the message. Then message recipients will get the parsed message with its OG metadata object through the onMessage() method in the channel event handler of the SDK. On the other hand, the message sender will do the same through onMessagesUpdated().

Displaying an OG metadata object is available for two subtypes of BaseMessage: UserMessage and AdminMessage. If the content of a BaseMessage object includes a web page URL containing OG metadata, the BaseMessage.ogMetaData property returns OGMetaData and OGImage objects.

If Sendbird server doesn’t have cache memory of the OG metadata of the given URL, the BaseMessage.ogMetaData property can return null due to the time it takes to fetch the OG metadata from the corresponding remote web page. In the meantime, the message text containing the URL will be delivered first to message recipients’ client app through the onMessageReceived() method. When the server completes fetching, the onMessagesUpdated() method will be called and the message with its OG metadata object will be delivered to the recipients’ client app. However, if Sendbird server has already cached the OG metadata of the URL, the BaseMessage.ogMetaData property returns the message and its OGMetaData object instantly and the onMessagesUpdated() method won’t be called.

// Send a user message containing the URL of a web page.
val params = UserMessageCreateParams("sendbird.com")
groupChannel.sendUserMessage(params) { message, e ->
    if (e != null) {
        // Handle error.
    }

    ...
}
// Receive a user message containing OG metadata of the web page through a channel event handler.
SendbirdChat.addChannelHandler(
    UNIQUE_HANDLER_ID,
    object : GroupChannelHandler() {
        override fun onMessageReceived(channel: BaseChannel, message: BaseMessage) {
            val ogMetaData = message.ogMetaData
            if (ogMetaData == null) {
                // The getOgMetaData() returns null if the message doesn’t have an OGMetadata object yet.
            } else {
                // You can create and customize the URL link preview by using the Open Graph metadata of the message.
                val url = ogMetaData.url
            }
        }

        override fun onMessagesUpdated(channel: BaseChannel, message: BaseMessage) {
            val ogMetaData = message.ogMetaData
            if (ogMetaData == null) {
                return
            } else {
                // You can create and customize the URL link preview by using the Open Graph metadata of the message.
                val url = ogMetaData.url
            }
        }
    }
)

Categorize channels by custom type

When creating a group channel, you can additionally specify a custom channel type to subclassify group channels. This custom type takes on the form of a String, and can be useful in searching or filtering group channels.

The data and customType properties of a channel object allow you to append information to your channels. While both properties can be used flexibly, common examples for customType include categorizing channels into School or Work.

val users = listOf("Tyler", "Nathan")
val params = GroupChannelCreateParams()
    .addUserIds(users)
    .setName(NAME)
    .setCustomType(CUSTOM_TYPE)
GroupChannel.createChannel(params) { channel, e ->
    if (e != null) {
        // Handle error.
    }

    ...
}

To get a channel's custom type, use the groupChannel.customType property.


Categorize messages by custom type

When sending a message, you can additionally specify a custom message type to subclassify messages. This custom type takes on the form of a String, and can be useful in searching or filtering messages.

The data and customType properties of a message object allow you to append information to your messages. While both properties can be used flexibly, common examples for customType include categorizing messages into Notes or Contacts.

To embed a custom type into your message, assign a value to customType under the UserMessageCreateParams or FileMessageCreateParams object. Then, pass the specified object as an argument to the parameter in the sendUserMessage() or sendFileMessage() method.

val params = UserMessageCreateParams(TEXT_MESSAGE)
    .setCustomType(CUSTOM_TYPE)

groupChannel.sendUserMessage(params) { message, e ->
    if (e != null) {
        // Handle error.
    }

    ...
}

To get a message's custom type, use the message.customType property.


Search channels by name, URL, or other filters

You can search for specific group channels by using several types of search filters within the GroupChannelListQuery and PublicGroupChannelListQuery classes.

GroupChannelListQuery

A GroupChannelListQuery instance provides many types of search filters such as channelNameContainsFilter and channelUrlsFilter. You can use these filters to search for specific private group channels.

The sample code below shows the query instance, which returns a list of the current user's group channels that partially match the specified keyword in channelNameContainsFilter in their' name.

val query = GroupChannel.createMyGroupChannelListQuery()
query.isIncludeEmpty = true
query.channelNameContainsFilter = "Sendbird"
query.next { channels, e ->
    if (e != null) {
        // Handle error.
    }

    // Through the channels parameter of the onResult() callback method, which Sendbird server has passed a result list to,
    // A list of group channels that have "Sendbird" in their names is returned.
    ...
}

The following shows the query instance, which returns a list of the current user's group channels that partially match the specified keyword in channelUrlsFilter in their URL.

val query = GroupChannel.createMyGroupChannelListQuery()
query.isIncludeEmpty = true
query.channelUrlsFilter = listOf("seminar", "lecture")
query.next { channels, e ->
    if (e != null) {
        // Handle error.
    }

    // Through the channels parameter of the onResult() callback method,
    // which Sendbird server has passed a result list to,
    // a list of group channels that have "seminar" or "lecture" in their URLs is returned.
    ...
}

The following table shows all supported filters for GroupChannelListQuery to search for specific channels you want to retrieve. You can use any filters in a similar fashion with the sample code above.

List of filters

NameFilters

CustomTypesFilter

Group channels with one or more specified custom types. You can enable this filter using the customTypesFilter method.

CustomTypeStartsWithFilter

Group channels with a custom type that starts with the specified value. You can enable this filter using the customTypeStartsWithFilter method.

ChannelNameContainsFilter

Group channels that contain the specified value in their names. You can enable this filter using the channelNameContainsFilter method.

ChannelUrlsFilter

Group channels with one or more specified channel URLs. You can enable this filter using the channelUrlsFilter method.

SuperChannelFilter

Either super or nonsuper group channels. Using the superChannelFilter method, you can enable this filter.

PublicChannelFilter

Either public or private group channels. Using the publicChannelFilter method, you can enable this filter.

UnreadChannelFilter

Group channels with one or more unread messages. Using the unreadChannelFilter method, you can enable this filter.

HiddenChannelFilter

Group channels with the specified state and operating behavior. You can enable this filter using the hiddenChannelFilter method.

MemberStateFilter

Group channels based on whether the user has accepted an invitation, or whether the user was invited by a friend. You can enable this filter using the memberStateFilter method.

UserIdsExactFilter

Group channels that contain members with one or more specified user IDs. You can enable this filter using the userIdsExactFilter method.

UserIdsIncludeFilter

Group channels that include one or more members with the specified user IDs. You can enable this filter using the userIdsIncludeFilter method.

NicknameContainsFilter

Group channels with members whose nicknames contain the specified value. You can enable this filter using the nicknameContainsFilter method.

MetaDataOrderKeyFilter

Group channels with metadata containing an item with the specified value as its key. This filter is effective only when the metadata are sorted in alphabetical order. You can enable this filter using the metaDataOrderKeyFilter method.

PublicGroupChannelListQuery

A PublicGroupChannelListQuery instance provides many types of search filters such as channelNameContainsFilter and channelUrlsFilter. You can use these filters to search for specific public group channels.

The sample code below shows the query instance, which returns a list of the current user's group channels that partially match the specified keyword in channelNameContainsFilter in their name.

val query = GroupChannel.createPublicGroupChannelListQuery()
query.includeEmpty = true
query.channelNameContainsFilter = "Sendbird"
query.next { channels, e ->
    if (e != null) {
        // Handle error.
    }

    // Through the channels parameter of the onResult() callback method,
    // which Sendbird server has passed a result list to,
    // a list of group channels that have "Sendbird" in their names is returned.
    ...
}

The following shows the query instance, which returns a list of the current user's group channels that partially match the specified keyword in channelUrlsFilter in their URL.

val query = GroupChannel.createPublicGroupChannelListQuery()
query.includeEmpty = true
query.channelUrlsFilter = listOf("seminar", "lecture")
query.next { channels, e ->
    if (e != null) {
        // Handle error.
    }

    // Through the channels parameter of the onResult() callback method,
    // which Sendbird server has passed a result list to,
    // a list of group channels that have "seminar" or "lecture" in their URLs is returned.
    ...
}

The following table shows all supported filters for PublicGroupChannelListQuery to search for specific channels you want to retrieve. You can use any filters in a similar fashion with the sample code above.

List of filters

NameFilters

customTypesFilter

Group channels with one or more specified custom types. You can enable this filter using the customTypesFilter method.

customTypeStartsWithFilter

Group channels with a custom type that starts with the specified value. You can enable this filter using the customTypeStartsWithFilter method.

channelNameContainsFilter

Group channels that contain the specified value in their names. You can enable this filter using the channelNameContainsFilter method.

channelUrlsFilter

Group channels with one or more specified channel URLs. You can enable this filter using the channelUrlsFilter method.

superChannelFilter

Either super or nonsuper group channels. Using the superChannelFilter method, you can enable this filter.

MembershipFilter

Group channels with specified membership. Using the membershipFilter method, you can enable this filter.

metaDataOrderKeyFilter

Group channels with metadata containing an item with the specified value as its key. This filter is effective only when the metadata are sorted in alphabetical order. You can enable this filter using the metaDataOrderKeyFilter method.


Search messages by keyword

Message search is a feature that retrieves a list of messages that contain a search query or a specified keyword.

Implement MessageSearchQuery to search messages in your Android client app. The query will retrieve a list of messages that contain a search term and meet the optional parameter values set by the MessageSearchQuery.Builder() method.

You can create the query instance in two ways. First, you can do so with the default values.

val query = SendbirdChat.createMessageSearchQuery(MessageSearchQuery.Builder())

Or, you can create an instance by changing those values to your preference.

val builder = MessageSearchQuery.Builder()
    .setKeyword("Sendbird")
    .setLimit(10)
    ...
    .build()
val query = SendbirdChat.createMessageSearchQuery(builder)

The query will retrieve a list of matched messages. Calling the builder method again will return the next page of the results.

query.next { messages, e ->
    if (e != null) {
        // Handle error.
    }

    ...
}

Use the hasNext method to see if there is a next page.

query.hasNext

Use the isLoading() method to see if the search results are loading.

query.isLoading

MessageQuerySearch.Builder()

You can build the query class using the following parameters, which allows you to add various search options.

Parameter nameTypeDescription

keyword

string

Specifies the search term.

* If the specified search term includes special characters or punctuations, it will return an error.

channelUrl

string

Specifies the URL of the target channel.

channelCustomType

string

Specifies the custom channel type.

limit

int

Specifies the number of messages to return per page. Acceptable values are 1 to 99, inclusive. (Default: 20)

exactMatch

boolean

Determines whether to search for messages that exactly match the search term. If set to false, it will return partial matches that contain the search term. (Default: false)

messageTimestampFrom

long

Restricts the search scope to the messages sent after the specified value in Unix milliseconds format. This includes the messages sent exactly on the timestamp. (Default: 0)

messageTimestampTo

long

Restricts the search scope to the messages sent before the specified value in Unix milliseconds format. This includes the messages sent exactly on the timestamp. (Default: Long.MAX_VALUE)

order

enum

Determines by which field the results are sorted. Acceptable values are SCORE, which is a relevance score, and TIMESTAMP, which indicates the time when a message was created. (Default: SCORE)

reverse

boolean

Determines whether to sort the results in reverse order. If set to false, they will be sorted in descending order. (Default: false)


Generate thumbnails of a file message

When sending an image file, you can determine whether to create thumbnails of the image to fetch and render into your UI. You can specify up to 3 different dimensions to generate thumbnail images in, which can be convenient for supporting various display densities.

Note: Supported file types are files whose media type is image/* or video/*. The Chat SDK doesn't support creating thumbnails when sending a file message via a file URL.

The sendFileMessage() method requires passing a FileMessageCreateParams object as an argument to a parameter, containing an array of items which each specify the maximum values of width and height of a thumbnail image. The callback function subsequently returns a list of Thumbnail items that each contain the URL of the generated thumbnail image file.

// Creating and adding a ThumbnailSize object (allowed number of thumbnail images: 3).
val thumbnailSizes = listOf(
    FileMessage.ThumbnailSize(100, 200),
    FileMessage.ThumbnailSize(200, 200)
)
val params = FileMessageCreateParams()
    .setFile(FILE)
    .setFileName(FILE_NAME)
    .setFileSize(FILE_SIZE)
    .setMimeType(MIME_TYPE)
    .setThumbnailSizes(thumbnailSizes)

groupChannel.sendFileMessage(params) { message, e ->
    if (e != null) {
        // Handle error.
    }
    if (message == null) return@sendFileMessage
    val first = message.thumbnails[0]
    val second = message.thumbnails[1]
    val maxHeightFirst = first.maxHeight // 100
    val maxHeightSecond = second.maxHeight // 200

    val urlFirst = first.url // The URL of first thumbnail file.
    val urlSecond = second.url // the URL of second thumbnail file.
}

A thumbnail image is generated evenly to fit within the bounds of maxWidth and maxHeight, which are provided through the ThumbnailSize constructor. Note that if the original image is smaller than the specified dimensions, the thumbnail isn't resized. url returns the location of the generated thumbnail file within Sendbird server.


Track file upload progress using a handler

You can track the file upload progress by passing FileMessageWithProgressHandler as an argument to a parameter when calling the sendFileMessage() method.

val params = FileMessageCreateParams(FILE)
    .setFileName(FILE_NAME)
    .setData(DATA)
    .setCustomType(CUSTOM_TYPE)

val fileMessage = groupChannel.sendFileMessage(
    params,
    object : FileMessageWithProgressHandler {
        override fun onProgress(bytesSent: Int, totalBytesSent: Int, totalBytesToSend: Int) {
            val percent = (totalBytesSent * 100) / totalBytesToSend
        }

        override fun onResult(message: FileMessage?, e: SendbirdException?) {
            if (e != null) {
                // Handle error
            }

            // Do something with the sent file message.
            ...
        }
    }
)

Cancel an in-progress file upload

Using the cancelFileMessageUpload() method, you can cancel an in-progress file upload while it's not completed yet. If the function operates successfully, true is returned.

Note: If you attempt to cancel the uploading after it is already completed, or canceled, or returned an error, the function returns false.

val params = FileMessageCreateParams(FILE)
    .setFileName(FILE_NAME)
    .setData(DATA)
    .setCustomType(CUSTOM_TYPE)

val fileMessage = groupChannel.sendFileMessage(params) { message, e ->
    ...
}

// Cancel uploading a file in the file message.
val isCanceled = groupChannel.cancelFileMessageUpload(fileMessage.requestId)

Share an encrypted file with other members

This file encryption feature prevents users without access from opening and reading encrypted files that have been shared within a group of users. When this feature is turned on, all types of sent files and thumbnail images will be first uploaded to Sendbird server, and then encrypted by AES256.

In a group channel, encrypted files and thumbnail images will be decrypted and accessed securely only by the members. Anyone outside of the channel and application won't have access to those files and thumbnail images. The following explains how this data security works and what to do at the SDK level to apply it to your client apps.

The Sendbird system enables secure encryption and decryption of files by generating and distributing an opaque and unique encryption key for each user. An encryption key is managed internally by the system, and is valid for three days. It is generated every time the user logs in to Sendbird server through the Chat SDK, which then gets delivered to the Chat SDK from the server.

When the Chat SDK requests an encrypted file by its URL, the auth parameter should be added to the URL to access the file, which is specified with an encryption key of the user such as ?auth=RW5jb2RlIHaXMgdGV4eA==. With the specified key in the auth parameter, Sendbird server first decrypts the file, then checks if the user is a member of the group channel, and finally, allows the user to access and open the file in the channel.

This can be easily done by using the fileMessage.url method, which automatically adds the auth parameter with an encryption key of the current user to the file URL, and returns the unique URL for the user.


Spam flood protection

This feature allows you to customize the number of messages a member can send in a group channel per second. By doing so, all excess messages will be deleted and only the number of messages allowed to be sent per member per second will be delivered. This feature protects your app from some members spamming others in the channel with the same messages.

Note: Our default system setting is five messages per second. This limit can be manually adjusted only from our side. Contact our sales team for further assistance.


Message auto-translation

It is possible for text messages to be sent in different languages through the Sendbird's auto-translation feature. When sending a text message, set List of language codes to a UserMessageCreateParams object and then pass the object as an argument to a parameter in the sendUserMessage() method to request translated messages in the corresponding languages.

Note: Message auto-translation is powered by Google Cloud Translation API recognition engine. Find language codes supported by the engine in the Miscellaneous page or visit the Language Support page in Google Cloud Translation.

val translationTargetLanguages = listOf(
    "es",   // Spanish
    "ko"    // Korean
)

val params = UserMessageCreateParams(TEXT_MESSAGE)
    .setCustomType(CUSTOM_TYPE)
    .setData(DATA)
    .setTranslationTargetLanguages(translationTargetLanguages)

groupChannel.sendUserMessage(params) { message, e ->
    if (e != null) {
        // Handle error.
    }

        ...
}

You can retrieve translations of a text message using userMessage.translations which returns a Map object containing the language codes and translations.

SendbirdChat.addChannelHandler(
    UNIQUE_HANDLER_ID,
    object : GroupChannelHandler() {
        override fun onMessageReceived(channel: BaseChannel, message: BaseMessage) {
            if (message is UserMessage) {
                val map = message.translations
                val esTranslatedMessage = map["es"] // Spanish

                // Display translation in the UI.
            }
        }
    }
)

Note: To enable this feature, contact our sales team.


Message on-demand translation

Using the groupChannel.translateUserMessage() method, you can allow your users to translate text messages into other languages when needed.

Note: Message on-demand translation is powered by Google Cloud Translation API recognition engine. Find language codes supported by the engine in the Miscellaneous page or visit the Language Support page in Google Cloud Translation.

val translationTargetLanguages = listOf(
    "es",   // Spanish
    "de"    // German
)

// The USER_MESSAGE argument below indicates a UserMessage object which represents an already sent or received text message.
groupChannel.translateUserMessage(USER_MESSAGE, translationTargetLanguages) { message, e ->
    if (message != null) {
        val map = message.translations
        val esTranslatedMessage = map["es"] // Spanish
        val deTranslatedMessage = map["de"] // German
        ...

        // Display translation in the UI.
    }
}

Based on this method, you can implement features such as real-time or instant translation to your app. You can also implement to only translate a selected message into preferred languages.

Note: To enable this feature, contact our sales team.