UI Components

GitHub version

Additional resources: GitHub Repo, API Reference, Code Samples

Getting Started

Make sure your application has been configured to use Bit6 Android SDK.

Add Bit6 UI library in your module build.gradle dependencies

dependencies {
    compile "com.bit6.ui:bit6-ui:0.9.7"
}

Contacts

Contact Source

Use Contact and ContactSource interfaces to provide the display names and avatars for each identity.

public interface Contact {
    /**
     * @return display name of contact
     */
    public String getDisplayName();

    /**
     * @return Uri of contact avatar
     */
    public String getAvatarUri();
}
public interface ContactSource {
    /**
     * Get contact by identity
     * @param identity String
     * @return {@link com.bit6.ui.Contact}
     */
    Contact get(String identity);
}

Avatar

AvatarView is an image view to display contact's avatar. In case the contact does not have an avatar image, the view will show the first letter of the contact name.

<com.bit6.ui.AvatarView android:id="@+id/avatar"
    android:layout_width="50dp"
    android:layout_height="50dp" />
AvatarView avatar = (AvatarView) findViewById(R.id.avatar);
avatar.init(name, uri);

Calls

InCall UI

InCallView handles rendering of video feeds and displaying common call controls. You can add multiple calls into the same user interface.

For more information please refer to our sample-app

<com.bit6.ui.InCallView
    android:id="@+id/incall_view"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" />
InCallView inCallView = (InCallView) findViewById(R.id.incall_view);
inCallView.init(contactSource);

Incoming Calls

The library offers multiple classes to simplify incoming call handling.

IncomingCallReceiver handles the broadcasts sent by the core SDK for the incoming calls and triggers the display of IncomingCallActivity.

<!-- Add to Manifest.xml -->
<receiver android:name="com.bit6.ui.IncomingCallReceiver" >
    <intent-filter>
        <action android:name="your.package.name.BIT6_INCOMING_CALL" />
    </intent-filter>
</receiver>

<activity
    android:name="com.bit6.ui.IncomingCallActivity"
    android:launchMode="singleTop"
    android:theme="@style/Theme.AppCompat.NoActionBar"
/>

Once you have a call in progress, and want to handle other incoming calls within your application UI, can temporarily disable this broadcast receiver by calling IncomingCallReceiver.setAlreadyInCall(true);

IncomingCallView allows you to present the information about the incoming call.

<com.bit6.ui.IncomingCallView
        android:id="@+id/incoming_call_view"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />
IncomingCallView incomingCallView = (IncomingCallView) findViewById(R.id.incoming_call_view);
RtcDialog dialog = callClient.getDialogFromIntent(getIntent());
incomingCallView.init(dialog, cs);

Conversations

Avatars

ConversationAvatarView contains up to two AvatarViews to show contacts avatars for a group conversation.

<com.bit6.ui.ConversationAvatarView android:id="@+id/avatar"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
avatars = (ConversationAvatarView) view.findViewById(R.id.avatars);
avatars.init(name1, uri1, name2, uri2);

ConversationList

ConversationList is a list of Conversations taken from conversations table.

<com.bit6.ui.ConversationList
    android:id="@+id/conversation_list"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>
ConversationList conversationList = (ConversationList)findViewById(R.id.conversation_list);
# Inititalize the component
conversationList.init(contactSource);

A tap on a conversation, will trigger an Intent.ACTION_VIEW

To handle this intent add <intent-filter> to your activity. Make sure to set android:exported="false" to catch actions only from this application.

<activity
    android:name="com.bit6.samples.demo.ChatActivity"
    android:exported="false">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <data android:mimeType="vnd.android.cursor.item/vnd.bit6.conversation" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

Long-press on a conversation will allow the user to delete the selected conversation.

ConversationView

ConversationView is convenience class containing two components: MessageList and ComposeView.

<com.bit6.ui.ConversationView
    android:id="@+id/conversation"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
ConversationView conversationView = (ConversationView)findViewById(R.id.conversation);
# Make sure to initialize the view before using it
conversationView.init("usr:john", contactSource);

There are multiple init() methods to initialize this view. The common theme for all of them is to provide the source of the messages and the destination to send the new messages to. In all cases you need to specify a ContactSource instance to allow the components show display names and avatars for your contacts. Available options:

a) Remote party identity:

conversationView.init("usr:john", contactSource);

b) messages cursor and destination address

conversationView.init(messagesCursor, "usr:john", contactSource);

c) conversation content URI

Uri uri = Uri.withAppendedPath(Contract.Conversations.CONTENT_URI_BY_IDENTITY, sender);
# or
# Uri uri = Uri.withAppendedPath(Contract.Conversations.CONTENT_URI, conv_id);
conversationView.init(uri, contactSource);

d) conversation _id in the database table

conversationView.init(_id, contactSource);

ComposeView

ComposeView allows to send text and attachment messages to a destination

<com.bit6.ui.ComposeView
    android:id="@+id/compose_area"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"/>
ComposeView composeView = (ComposeView) findViewById(R.id.compose_area);
# Make sure to set destination before sending the message.
composeView.setDestination(Address.parse("usr:john"));

If your app need to perform any actions before sending the message you can set ComposeView.Listener.

public interface Listener {
    /**
    * Called right before sending the message
    * @param message OutgoingMessage which will be sent if this method returns true
    * @return true if the message should be sent, otherwise return false
    */
    boolean onBeforeSend(OutgoingMessage message);
}
composeView.setListener(listener);

ComposeView has a popup menu in the left corner. You can specify the items to be displayed there.

ActionItem[] items = new ActionItem[]{
        new ActionItem(getString(R.string.choose_photo), R.drawable.ic_action_picture) {
            @Override
            public void run() {
                MediaUtils.showImageChooser(ChatActivity.this);
            }
        },
        ...
};
composeView.setActionItems(items);

ActionItem is an abstract class which has title, icon and run() method which is called when the item is selected. So each action item you set will be converted to menu item of popup menu.

You can set attachment to the message being composed using either:

  1. composeView.setAttachment(path, contentType);, or

  2. via an Intent - it must contain attachment URI and content type

Intent intent = new Intent();
intent.setDataAndType(attachmentUri, contentType);
composeView.setAttachment(intent);

To clear text or attachment from ComposeView

composeView.clear();

Messages

MessageList

MessageList is a list view which shows messages from provided cursor

<com.bit6.ui.MessageList
    android:id="@+id/messages"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"/>
MessageList messageList = (MessageList)findViewById(R.id.messages);
Cursor messages = getContext().getContentResolver().query(Contract.Messages.CONTENT_URI, null,
       Contract.Messages.CONVERSATION_ID + "=?", new String[] {
               "" + _id
       },
       Contract.Messages.CREATED + " ASC");
# Initialize the component
messageList.init(cursor, isGroupChat, cs);

On long press, a context menu is displayed allowing the user to delete individual messages.

MessageList marks new messages as read if setMarkAsReadOnView(true) was called.

Incoming Messages

When a new message arrives, the core SDK sends a broadcast about a new incoming message with the action your.package.name.BIT6_INCOMING_MESSAGE

You can register a broadcast receiver either in the app code or in Manifest.xml

<receiver
    android:name="com.bit6.ui.IncomingMessageReceiver"
    android:enabled="true" >
        <intent-filter>
            <action android:name="package.BIT6_INCOMING_MESSAGE" />
        </intent-filter>
</receiver>

The default IncomingMessageReceiver implementation:

  1. displays an Android system notification about the new message

  2. when user taps on the notification, it fires an Intent with ACTION_VIEW and Conversation URI

NOTE: This is exactly the same Intent type used when the user taps on a conversation in the ConversationList component.

To handle this intent, the app can provide an intent handler in the Manifest or app code.

<activity
    android:name="ChatActivity"
    android:exported="false">
        <intent-filter>
            <action android:name="android.intent.action.VIEW"/>
            <data android:mimeType="vnd.android.cursor.item/vnd.bit6.conversation"/>
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
</activity>

When you are in a conversation screen and chatting with a specific user, you do not want to display system Android notifications for this chat. Simply call: IncomingMessageReceiver.setConversationId("usr:john") to disable them.

When done chatting with this user, call IncomingMessageReceiver.setConversationId(null) to start seeing Android notifications for the new messages from this user.

Media

VideoRecorder

VideoRecorder allows to record video with good quality and reasonable size.

<com.bit6.ui.VideoRecorder android:id="@+id/video_recorder"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
VideoRecorder videoRecorder = (VideoRecorder) findViewById(R.id.video_recorder);
videoRecorder.init(activity, listener);

After video is recorded you will receive video file uri and content type by listener's onVideoRecorded() method.

@Override
public void onVideoRecorded(Uri uri, String contentType) {

}

Make sure to destroy the recorder after using it.

videoRecorder.destroy();

Utilities

MediaUtils helper class provides a number of convienice method simplifing the process of accessing the camera, shoing images choosed, working with locations, checking and requesting permissions

Photo Camera

showPhotoCamera(Activity activity)

Image Chooser

showImageChooser(Activity activity)

Video Recorder

showVideoRecorder(Activity activity)

You can register com.bit6.ui.VideoRecorderActivity in your Manifest.xml:

<activity
    android:name="com.bit6.ui.VideoRecorderActivity"
    android:screenOrientation="portrait"
    android:exported="false">
        <intent-filter>
            <action android:name="com.bit6.ui.record_video"/>
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
</activity>

Location

requestMyLocation(Activity activity)

Helper methods

If you have used one of the convenience methods described above, you need to override activities methods to handle the responese:

In Activity.onActivityResult(), call MediaUtils.getAttachmentFromActivityResult(). If it returns non-null value, it means an attachment was selected and can be used in message composer.

In Activity.onRequestPermissionsResult(), call MediaUtils.onRequestPermissionsResult() to handle the responses to the permission requests.