Demo App
An app demonstrating consumption of Huddle01 Android SDK
Initialization
public class Application extends android.app.Application {
@Override
public void onCreate() {
super.onCreate();
HuddleClient.initApp(this);
}
}
UI
Java
public class MeView extends RelativeLayout {
public MeView(@NonNull Context context) {
super(context);
init(context);
}
public MeView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public MeView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public MeView(
@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
com.rohg007.android.huddle01_android_sdk.databinding.ViewMeBindingImpl mBinding;
private void init(Context context) {
mBinding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.view_me, this, true);
mBinding.peerView.videoRenderer.init(PeerConnectionUtils.getEglContext(), null);
}
public void setProps(MeProps props, final HuddleClient huddleClient) {
// set view model.
mBinding.peerView.setPeerViewProps(props);
// register click listener.
mBinding.peerView.info.setOnClickListener(
view -> {
Boolean showInfo = props.getShowInfo().get();
props.getShowInfo().set(showInfo != null && showInfo ? Boolean.FALSE : Boolean.TRUE);
});
mBinding.peerView.meDisplayName.setOnEditorActionListener(
(textView, actionId, keyEvent) -> {
if (actionId == EditorInfo.IME_ACTION_DONE) {
huddleClient.changeDisplayName(textView.getText().toString().trim());
return true;
}
return false;
});
mBinding.peerView.videoRenderer.setZOrderMediaOverlay(true);
// set view model.
mBinding.setMeProps(props);
// register click listener.
mBinding.mic.setOnClickListener(
view -> {
if (MeProps.DeviceState.ON.equals(props.getMicState().get())) {
huddleClient.muteMic();
} else {
huddleClient.unmuteMic();
}
});
mBinding.cam.setOnClickListener(
view -> {
if (MeProps.DeviceState.ON.equals(props.getCamState().get())) {
huddleClient.disableCam();
} else {
huddleClient.enableCam();
}
});
mBinding.changeCam.setOnClickListener(view -> huddleClient.changeCam());
}
}
public class PeerView extends RelativeLayout {
public PeerView(@NonNull Context context) {
super(context);
init(context);
}
public PeerView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public PeerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public PeerView(
@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
com.rohg007.android.huddle01_android_sdk.databinding.ViewPeerBinding mBinding;
private void init(Context context) {
mBinding =
DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.view_peer, this, true);
mBinding.peerView.videoRenderer.init(PeerConnectionUtils.getEglContext(), null);
}
public void setProps(PeerProps props) {
// set view model into included layout
mBinding.peerView.setPeerViewProps(props);
// register click listener.
mBinding.peerView.info.setOnClickListener(
view -> {
Boolean showInfo = props.getShowInfo().get();
props.getShowInfo().set(showInfo != null && showInfo ? Boolean.FALSE : Boolean.TRUE);
});
// set view model
mBinding.setPeerProps(props);
}
}
public class PeerAdapter extends RecyclerView.Adapter<PeerAdapter.PeerViewHolder> {
private static final String TAG = "PeerAdapter";
@NonNull private StateStore mStore;
@NonNull private LifecycleOwner mLifecycleOwner;
private List<Peer> mPeers = new LinkedList<>();
private int containerHeight;
public PeerAdapter(
@NonNull StateStore store,
@NonNull LifecycleOwner lifecycleOwner) {
mStore = store;
mLifecycleOwner = lifecycleOwner;
}
public void replacePeers(@NonNull List<Peer> peers) {
mPeers = peers;
notifyDataSetChanged();
}
@NonNull
@Override
public PeerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
containerHeight = parent.getHeight();
Context context = parent.getContext();
View view = LayoutInflater.from(context).inflate(R.layout.item_remote_peer, parent, false);
return new PeerViewHolder(
view, new PeerProps(((AppCompatActivity) context).getApplication(), mStore));
}
@Override
public void onBindViewHolder(@NonNull PeerViewHolder holder, int position) {
// update height
ViewGroup.LayoutParams layoutParams = holder.mPeerView.getLayoutParams();
layoutParams.height = getItemHeight();
holder.mPeerView.setLayoutParams(layoutParams);
// bind
holder.bind(mLifecycleOwner, mPeers.get(position));
}
@Override
public int getItemCount() {
return mPeers.size();
}
private int getItemHeight() {
int itemCount = getItemCount();
if (itemCount <= 1) {
return containerHeight;
} else if (itemCount <= 3) {
return containerHeight / itemCount;
} else {
return (int) (containerHeight / 3.2);
}
}
static class PeerViewHolder extends RecyclerView.ViewHolder {
@NonNull
final PeerView mPeerView;
@NonNull final PeerProps mPeerProps;
PeerViewHolder(@NonNull View view, @NonNull PeerProps peerProps) {
super(view);
mPeerView = view.findViewById(R.id.remote_peer);
mPeerProps = peerProps;
}
void bind(LifecycleOwner owner, @NonNull Peer peer) {
mPeerProps.connect(owner, peer.getId());
mPeerView.setProps(mPeerProps);
}
}
}
public class BindingAdapters {
private static final String TAG = "BindingAdapters";
@BindingAdapter({"bind:edias_state", "bind:edias_state_animation"})
public static void roomState(
ImageView view, ConnectionState state, Animation animation) {
if (state == null) {
return;
}
if (ConnectionState.CONNECTING.equals(state)) {
view.setImageResource(R.drawable.ic_state_connecting);
view.startAnimation(animation);
} else if (ConnectionState.CONNECTED.equals(state)) {
view.setImageResource(R.drawable.ic_state_connected);
animation.cancel();
view.clearAnimation();
} else {
view.setImageResource(R.drawable.ic_state_new_close);
animation.cancel();
view.clearAnimation();
}
}
@BindingAdapter({"bind:edias_link"})
public static void inviteLink(TextView view, String inviteLink) {
view.setVisibility(TextUtils.isEmpty(inviteLink) ? View.INVISIBLE : View.VISIBLE);
}
@SuppressLint("SetTextI18n")
@BindingAdapter({"bind:edias_device"})
public static void deviceInfo(TextView view, DeviceInfo deviceInfo) {
if (deviceInfo == null) {
return;
}
int deviceIcon = R.drawable.ic_unknown;
if (!TextUtils.isEmpty(deviceInfo.getFlag())) {
switch (deviceInfo.getFlag().toLowerCase()) {
case "chrome":
deviceIcon = R.mipmap.chrome;
break;
case "firefox":
deviceIcon = R.mipmap.firefox;
break;
case "safari":
deviceIcon = R.mipmap.safari;
break;
case "opera":
deviceIcon = R.mipmap.opera;
break;
case "edge":
deviceIcon = R.mipmap.edge;
break;
case "android":
deviceIcon = R.mipmap.android;
break;
}
view.setText(deviceInfo.getName() + " " + deviceInfo.getVersion());
} else {
view.setText("");
}
view.setCompoundDrawablesWithIntrinsicBounds(deviceIcon, 0, 0, 0);
}
@BindingAdapter({"edias_mic_state"})
public static void deviceMicState(ImageView imageView, MeProps.DeviceState state) {
if (state == null) {
return;
}
if (MeProps.DeviceState.ON.equals(state)) {
imageView.setBackgroundResource(R.drawable.bg_media_box_on);
} else {
imageView.setBackgroundResource(R.drawable.bg_media_box_off);
}
switch (state) {
case ON:
imageView.setImageResource(R.drawable.icon_mic_black_on);
break;
case OFF:
imageView.setImageResource(R.drawable.icon_mic_white_off);
break;
case UNSUPPORTED:
imageView.setImageResource(R.drawable.icon_mic_white_unsupported);
break;
}
}
@BindingAdapter({"edias_cam_state"})
public static void deviceCamState(ImageView imageView, MeProps.DeviceState state) {
if (state == null) {
return;
}
if (MeProps.DeviceState.ON.equals(state)) {
imageView.setBackgroundResource(R.drawable.bg_media_box_on);
} else {
imageView.setBackgroundResource(R.drawable.bg_media_box_off);
}
switch (state) {
case ON:
imageView.setImageResource(R.drawable.icon_webcam_black_on);
break;
case OFF:
imageView.setImageResource(R.drawable.icon_webcam_white_off);
break;
case UNSUPPORTED:
imageView.setImageResource(R.drawable.icon_webcam_white_unsupported);
break;
}
}
@BindingAdapter({"edias_change_came_state"})
public static void changeCamState(View view, MeProps.DeviceState state) {
if (state == null) {
return;
}
view.setEnabled(MeProps.DeviceState.ON.equals(state));
}
@BindingAdapter({"edias_share_state"})
public static void shareState(View view, MeProps.DeviceState state) {
if (state == null) {
return;
}
view.setEnabled(MeProps.DeviceState.ON.equals(state));
}
@BindingAdapter({"edias_render"})
public static void render(SurfaceViewRenderer renderer, VideoTrack track) {
if (track != null) {
track.addSink(renderer);
renderer.setVisibility(View.VISIBLE);
} else {
renderer.setVisibility(View.GONE);
}
}
@BindingAdapter({"edias_render_empty"})
public static void renderEmpty(View renderer, VideoTrack track) {
if (track == null) {
renderer.setVisibility(View.VISIBLE);
} else {
renderer.setVisibility(View.GONE);
}
}
}
XML
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/onboarding_"
android:orientation="vertical"
tools:context=".RoomActivity">
<EditText
android:id="@+id/chat_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginLeft="10dp"
android:layout_marginBottom="10dp"
android:imeOptions="actionDone"
android:singleLine="true" />
<ImageView
android:id="@+id/room_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="5dp"
android:padding="5dp"
android:src="@drawable/ic_state_new_close"
bind:edias_state="@{roomProps.connectionState}"
bind:edias_state_animation="@{roomProps.getConnectingAnimation}" />
<TextView
android:id="@+id/version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginTop="5dp"
android:layout_marginEnd="10dp"
android:padding="5dp"
android:textColor="@color/text_color" />
<TextView
android:id="@+id/invitation_link"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:background="@drawable/bg_area"
android:paddingLeft="15dp"
android:paddingTop="8dp"
android:paddingRight="15dp"
android:paddingBottom="8dp"
android:text="@string/invitation_link"
android:textColor="@color/text_color"
android:textSize="15sp"
bind:edias_link="@{roomProps.invitationLink}" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/remote_peers"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
<com.leinardi.android.speeddial.SpeedDialView
android:id="@+id/reaction_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/chat_input"
android:layout_alignParentEnd="true"
bind:sdMainFabClosedSrc="@drawable/ic_baseline_tag_faces_24" />
<com.rohg007.android.huddle01_android_sdk.views.MeView
android:id="@+id/me"
android:layout_width="220dp"
android:layout_height="200dp"
android:layout_alignParentBottom="true"
android:layout_marginLeft="10dp"
android:layout_marginBottom="60dp" />
</RelativeLayout>
<data>
<variable
name="roomProps"
type="com.rohg007.android.huddle01_android_sdk.viewmodels.RoomProps" />
</data>
</layout>
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<import type="android.view.View" />
<variable
name="meProps"
type="com.rohg007.android.huddle01_android_sdk.viewmodels.MeProps" />
</data>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
bind:cardBackgroundColor="@color/peer_bg_color"
bind:cardCornerRadius="16dp"
bind:cardUseCompatPadding="true">
<include
android:id="@+id/peer_view"
layout="@layout/view_peer_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
bind:peerViewProps="@{meProps}" />
<LinearLayout
android:id="@+id/controls"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:gravity="center_vertical"
android:padding="5dp"
android:visibility="@{meProps.connected ? View.VISIBLE : View.GONE}">
<ImageView
android:id="@+id/mic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="2dp"
android:background="@drawable/bg_media_box"
android:padding="5dp"
android:src="@drawable/icon_mic"
bind:edias_mic_state="@{meProps.micState}" />
<ImageView
android:id="@+id/cam"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="2dp"
android:background="@drawable/bg_media_box"
android:clickable="@{!(meProps.me.camInProgress || meProps.me.shareInProgress)}"
android:padding="5dp"
android:src="@drawable/icon_webcam"
bind:edias_cam_state="@{meProps.camState}" />
<ImageView
android:id="@+id/change_cam"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="2dp"
android:background="@drawable/bg_media_box"
android:clickable="@{!(meProps.me.camInProgress || meProps.me.shareInProgress)}"
android:padding="5dp"
android:src="@drawable/icon_change_cam"
bind:edias_change_came_state="@{meProps.camState}" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</layout>
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<import type="android.view.View" />
<variable
name="peerProps"
type="com.rohg007.android.huddle01_android_sdk.viewmodels.PeerProps" />
</data>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
bind:cardBackgroundColor="@color/peer_bg_color"
bind:cardCornerRadius="16dp"
bind:cardElevation="5dp"
bind:cardUseCompatPadding="true">
<include
android:id="@+id/peer_view"
layout="@layout/view_peer_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
bind:peerViewProps="@{peerProps}" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:padding="5dp">
<ImageView
android:id="@+id/mic_off"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_marginEnd="5dp"
android:clickable="false"
android:src="@drawable/ic_microphone_slash"
android:visibility="@{!peerProps.audioEnabled ? View.VISIBLE : View.GONE}" />
<ImageView
android:id="@+id/cam_off"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:clickable="false"
android:src="@drawable/ic_videocamera_slash"
android:visibility="@{!peerProps.videoVisible ? View.VISIBLE : View.GONE}" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</layout>
<?xml version="1.0" encoding="utf-8"?>
<com.rohg007.android.huddle01_android_sdk.views.PeerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/remote_peer"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<import type="androidx.core.util.Consumer" />
<import type="android.text.TextUtils" />
<import type="android.view.View" />
<variable
name="peerViewProps"
type="com.rohg007.android.huddle01_android_sdk.viewmodels.PeerViewProps" />
</data>
<FrameLayout
android:background="@color/peer_bg_color"
android:layout_width="match_parent"
android:layout_height="match_parent">
<org.webrtc.SurfaceViewRenderer
android:id="@+id/video_renderer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"
bind:edias_render="@{peerViewProps.videoTrack}" />
<LinearLayout
android:id="@+id/video_hidden"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
bind:edias_render_empty="@{peerViewProps.videoTrack}">
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<ImageView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="5"
android:scaleType="fitCenter"
android:src="@drawable/buddy" />
</LinearLayout>
<LinearLayout
android:id="@+id/peer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:gravity="start"
android:orientation="vertical"
android:background="@color/peer_display_name_bg_color"
android:padding="5dp">
<EditText
android:id="@+id/me_display_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@null"
android:textSize="14sp"
android:textStyle="bold"
android:textColor="@color/peer_display_name_text_color"
android:imeOptions="actionDone"
android:singleLine="true"
android:text="@{peerViewProps.peer.displayName}"
android:visibility="@{peerViewProps.me ? View.VISIBLE : View.GONE}"
android:layout_marginHorizontal="8dp"/>
<TextView
android:id="@+id/peer_display_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:singleLine="true"
android:text="@{peerViewProps.peer.displayName}"
android:textColor="@color/peer_display_name_text_color"
android:textSize="14sp"
android:textStyle="bold"
android:visibility="@{!peerViewProps.me ? View.VISIBLE : View.GONE}"
android:layout_marginHorizontal="8dp"/>
</LinearLayout>
</FrameLayout>
</layout>
Room
public class RoomActivity extends AppCompatActivity {
private static final String TAG = RoomActivity.class.getSimpleName();
private static final int REQUEST_CODE_SETTING = 1;
private String mRoomId, mPeerId, mDisplayName;
private ActivityRoomBinding activityRoomBinding;
private HuddleClient huddleClient;
private StateStore stateStore;
private String apiKey = API_KEY_HERE;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activityRoomBinding = DataBindingUtil.setContentView(this, R.layout.activity_room);
stateStore = new StateStore();
createRoom();
checkPermission();
setupReactions();
}
@SuppressLint("NonConstantResourceId")
private void setupReactions(){
activityRoomBinding.reactionFab.inflate(R.menu.reactions_menu);
activityRoomBinding.reactionFab.setOnActionSelectedListener(actionItem -> {
switch (actionItem.getId()){
case R.id.tears_of_joy: {
huddleClient.sendReaction(Reactions.TEARS_OF_JOY);
activityRoomBinding.reactionFab.close();
return true;
}
case R.id.crying_face: {
huddleClient.sendReaction(Reactions.CRYING_FACE);
activityRoomBinding.reactionFab.close();
return true;
}
case R.id.hundred: {
huddleClient.sendReaction(Reactions.HUNDRED);
activityRoomBinding.reactionFab.close();
return true;
}
case R.id.thumbs_up: {
huddleClient.sendReaction(Reactions.THUMBS_UP);
activityRoomBinding.reactionFab.close();
return true;
}
case R.id.thumbs_down: {
huddleClient.sendReaction(Reactions.THUMBS_DOWN);
activityRoomBinding.reactionFab.close();
return true;
}
case R.id.rocket: {
huddleClient.sendReaction(Reactions.ROCKET);
activityRoomBinding.reactionFab.close();
return true;
}
default: {
Toast.makeText(this, "invalid reaction", Toast.LENGTH_SHORT).show();
activityRoomBinding.reactionFab.close();
return false;
}
}
});
}
private void createRoom(){
loadRoomConfig();
activityRoomBinding.invitationLink.setText("RoomId: "+mRoomId);
huddleClient = new HuddleClient.Builder(getApplicationContext(), apiKey)
.setPeerId(mPeerId)
.setRoomId(mRoomId)
.setDisplayName(mDisplayName)
.setCanConsume(true)
.setCanProduce(true)
.setCanUseDataChannel(true)
.setRoomEventListener(listener)
.setMeListener(meListener)
.setFrontCamEnabledOnInit(true)
.build();
getViewModelStore().clear();
initViewModel();
}
void joinRoom(){
huddleClient.joinRoom();
}
private void loadRoomConfig(){
Intent intent = getIntent();
String roomId = intent.getStringExtra("roomId");
if(roomId!=null){
mRoomId = roomId;
} else {
mRoomId = Utils.getRandomString(8);
}
mPeerId = Utils.getRandomString(8);
mDisplayName = Utils.getRandomString(8);
}
private void initViewModel(){
EdiasProps.Factory factory = new EdiasProps.Factory(getApplication(), stateStore);
RoomProps roomProps = new ViewModelProvider(this, factory).get(RoomProps.class);
roomProps.connect(this);
activityRoomBinding.invitationLink.setOnClickListener(v -> {
String invitationLink = roomProps.getInvitationLink().get();
ClipboardCopy.clipboardCopy(getApplication(), invitationLink, R.string.invite_link_copied);
});
activityRoomBinding.setRoomProps(roomProps);
MeProps meProps = new ViewModelProvider(this, factory).get(MeProps.class);
meProps.connect(this);
activityRoomBinding.me.setProps(meProps, huddleClient);
activityRoomBinding.chatInput.setOnEditorActionListener((v, actionId, event) -> {
if(actionId == EditorInfo.IME_ACTION_DONE){
huddleClient.sendChatMessage(v.getText().toString());
v.setText("");
return true;
} else
return false;
});
PeerAdapter peerAdapter = new PeerAdapter(stateStore, this);
activityRoomBinding.remotePeers.setLayoutManager(new LinearLayoutManager(this));
activityRoomBinding.remotePeers.setAdapter(peerAdapter);
stateStore.getPeers().observe(this, peers -> {
List<Peer> peerList = peers.getAllPeers();
if(peerList.isEmpty()){
activityRoomBinding.remotePeers.setVisibility(View.GONE);
activityRoomBinding.roomState.setVisibility(View.VISIBLE);
} else {
activityRoomBinding.remotePeers.setVisibility(View.VISIBLE);
activityRoomBinding.roomState.setVisibility(View.GONE);
}
peerAdapter.replacePeers(peerList);
});
stateStore.getNotify().observe(this, notify -> {
SpannableStringBuilder text = SpannableStringBuilder.valueOf(notify.getText());
if(notify.getType().equals("error"))
text.setSpan(new ForegroundColorSpan(Color.RED), 0, text.length(), 0);
Toast.makeText(this, text, notify.getTimeout()).show();
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if(requestCode == REQUEST_CODE_SETTING){
destroyRoom();
createRoom();
joinRoom();
} else super.onActivityResult(requestCode, resultCode, data);
}
private void destroyRoom(){
huddleClient.closeRoom();
}
@Override
protected void onDestroy() {
super.onDestroy();
destroyRoom();
}
private void checkPermission() {
String[] permissions = {
Manifest.permission.INTERNET,
Manifest.permission.RECORD_AUDIO,
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
String rationale = "Please provide permissions";
Permissions.Options options =
new Permissions.Options().setRationaleDialogTitle("Info").setSettingsDialogTitle("Warning");
Permissions.check(this, permissions, rationale, options, permissionHandler);
}
private final PermissionHandler permissionHandler =
new PermissionHandler() {
@Override
public void onGranted() {
joinRoom();
}
};
private final RoomEventListener listener = new RoomEventListener() {
@Override
public void onRoomUrlGenerated(String roomId, String roomUrl) {
stateStore.setRoomUrl(roomId, roomUrl);
}
@Override
public void onRoomStateChanged(ConnectionState state) {
stateStore.setRoomState(state);
}
@Override
public void onError(String message) {
}
@Override
public void onPeerChanged(String actionType, String peerId, @Nullable JSONObject info, @Nullable String displayName) {
switch (actionType){
case Constants.ACTION_ADDED: stateStore.addPeer(peerId, info);
break;
case Constants.ACTION_DISPLAY_NAME_CHANGED: stateStore.setPeerDisplayName(peerId, displayName);
break;
case Constants.ACTION_REMOVED: stateStore.removePeer(peerId);
break;
default: Toast.makeText(getApplicationContext(), "Invalid Action Type", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onProducersChanged(String type, HuddleProducer producer) {
switch (type){
case Constants
.ACTION_ADDED: stateStore.addProducer(producer);
break;
case Constants.ACTION_PAUSED: stateStore.setProducerPaused(producer.getId());
break;
case Constants.ACTION_RESUMED: stateStore.setProducerResumed(producer.getId());
break;
case Constants.ACTION_REMOVED: stateStore.removeProducer(producer.getId());
break;
default: Toast.makeText(getApplicationContext(), "Invalid Producer Action Type", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onConsumerAdded(String peerId, String consumerType, HuddleConsumer consumer, boolean remotelyPaused) {
stateStore.addConsumer(peerId, consumerType, consumer, remotelyPaused);
}
@Override
public void onConsumerRemoved(String peerId, String consumerId) {
stateStore.removeConsumer(peerId, consumerId);
}
@Override
public void onConsumerStateChanged(String actionType, String consumerId, String originator) {
switch (actionType){
case Constants.ACTION_PAUSED: stateStore.setConsumerPaused(consumerId, originator);
break;
case Constants.ACTION_RESUMED: stateStore.setConsumerResumed(consumerId, originator);
break;
default: Toast.makeText(getApplicationContext(), "Invalid Action Type", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onDataProducerChanged(String actionType, HuddleDataProducer dataProducer) {
switch (actionType){
case Constants.ACTION_ADDED: stateStore.addDataProducer(dataProducer);
break;
case Constants.ACTION_REMOVED: stateStore.removeDataProducer(dataProducer.getId());
break;
default: Toast.makeText(getApplicationContext(), "Invalid Action Type", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onDataConsumerChanged(String actionType, String peedId, HuddleDataConsumer dataConsumer) {
switch (actionType) {
case Constants.ACTION_ADDED: stateStore.addDataConsumer(peedId, dataConsumer);
break;
case Constants.ACTION_REMOVED: stateStore.removeDataConsumer(peedId, dataConsumer.getId());
break;
default: Toast.makeText(getApplicationContext(), "Invalid Action Type", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onReactionReceived(Peer peer, String reaction) {
Toast.makeText(getApplicationContext(), peer.getDisplayName()+" reacted: "+reaction, Toast.LENGTH_SHORT).show();
}
@Override
public void onChatReceived(Peer peer, String message) {
Toast.makeText(getApplicationContext(), peer.getDisplayName()+" messaged: "+message, Toast.LENGTH_SHORT).show();
}
@Override
public void onNotification(Notify notify) {
Toast.makeText(getApplicationContext(), notify.getText(), Toast.LENGTH_SHORT).show();
}
};
private final MeListener meListener = new MeListener() {
@Override
public void onMeReceived(String peerId, String displayName, DeviceInfo deviceInfo) {
stateStore.setMe(peerId, displayName, deviceInfo);
}
@Override
public void onMediaCapabilitiesReceived(boolean canSendMic, boolean canSendCam) {
stateStore.setMediaCapabilities(canSendMic, canSendCam);
}
@Override
public void onNewDisplayName(String displayName) {
stateStore.setDisplayName(displayName);
}
};
}
State
public class StateStore {
CustomTypeMutableLiveData<RoomInfo> roomInfo = new CustomTypeMutableLiveData<>(RoomInfo::new);
CustomTypeMutableLiveData<Me> me = new CustomTypeMutableLiveData<>(Me::new);
CustomTypeMutableLiveData<Producers> producers = new CustomTypeMutableLiveData<>(Producers::new);
CustomTypeMutableLiveData<DataProducers> dataProducers = new CustomTypeMutableLiveData<>(DataProducers::new);
CustomTypeMutableLiveData<Peers> peers = new CustomTypeMutableLiveData<>(Peers::new);
CustomTypeMutableLiveData<Consumers> consumers = new CustomTypeMutableLiveData<>(Consumers::new);
CustomTypeMutableLiveData<DataConsumers> dataConsumers = new CustomTypeMutableLiveData<>(DataConsumers::new);
MutableLiveData<Notify> notify = new MutableLiveData<>();
public void setRoomUrl(String roomId, String url){
roomInfo.postValue(roomInfo->{
roomInfo.setRoomId(roomId);
roomInfo.setUrl(url);
});
}
public void setRoomState(ConnectionState state){
roomInfo.postValue(roomInfo->{
roomInfo.setConnectionState(state);
});
if(state == ConnectionState.CLOSED){
peers.postValue(Peers::clear);
me.postValue(Me::clear);
producers.postValue(Producers::clear);
consumers.postValue(Consumers::clear);
}
}
public void setMe(String peerId, String displayName, DeviceInfo device){
me.postValue(me->{
me.setId(peerId);
me.setDisplayName(displayName);
me.setDeviceInfo(device);
});
}
public void setMediaCapabilities(boolean canSendMic, boolean canSendCam){
me.postValue(me-> {
me.setCanSendMic(canSendMic);
me.setCanSendCam(canSendCam);
});
}
public void setDisplayName(String displayName){
me.postValue(me->me.setDisplayName(displayName));
}
public void addProducer(HuddleProducer producer){
producers.postValue(producers->producers.addProducer(producer));
}
public void setProducerPaused(String producerId){
producers.postValue(producers->producers.setProducerPaused(producerId));
}
public void setProducerResumed(String producerId){
producers.postValue(producers->producers.setProducerResumed(producerId));
}
public void removeProducer(String producerId){
producers.postValue(producers->producers.removeProducer(producerId));
}
public void addDataProducer(HuddleDataProducer dataProducer){
dataProducers.postValue(dataProducers->dataProducers.addDataProducer(dataProducer));
}
public void removeDataProducer(String dataProducerId){
dataProducers.postValue(dataProducers->dataProducers.removeDataProducer(dataProducerId));
}
public void addPeer(String peerId, JSONObject info){
peers.postValue(peers-> {
peers.addPeer(peerId, info);
});
}
public void setPeerDisplayName(String peerId, String displayName){
peers.postValue(peers->peers.setPeerDisplayName(peerId, displayName));
}
public void removePeer(String peerId){
roomInfo.postValue(roomInfo->{
if(!TextUtils.isEmpty(peerId) && roomInfo.getActiveSpeakerId().equals(peerId))
roomInfo.setActiveSpeakerId(null);
if(!TextUtils.isEmpty(peerId) && roomInfo.getStatsPeerId().equals(peerId))
roomInfo.setStatsPeerId(null);
});
peers.postValue(peers->peers.removePeer(peerId));
}
public void addConsumer(String peerId, String type, HuddleConsumer consumer, boolean remotelyPaused){
consumers.postValue(consumers->consumers.addConsumer(type, consumer, remotelyPaused));
peers.postValue(peers->peers.addConsumer(peerId, consumer));
}
public void removeConsumer(String peerId, String consumerId){
consumers.postValue(consumers->consumers.removeConsumer(consumerId));
peers.postValue(peers->peers.removeConsumer(peerId, consumerId));
}
public void setConsumerPaused(String consumerId, String originator){
consumers.postValue(consumers->consumers.setConsumerPaused(consumerId, originator));
}
public void setConsumerResumed(String consumerId, String originator){
consumers.postValue(consumers->consumers.setConsumerResumed(consumerId, originator));
}
public void addDataConsumer(String peerId, HuddleDataConsumer dataConsumer){
dataConsumers.postValue(dataConsumers->dataConsumers.addDataConsumer(dataConsumer));
peers.postValue(peers->peers.addDataConsumer(peerId, dataConsumer));
}
public void removeDataConsumer(String peerId, String dataConsumerId){
dataConsumers.postValue(dataConsumers->dataConsumers.removeDataConsumer(dataConsumerId));
peers.postValue(peers->peers.removeDataConsumer(peerId, dataConsumerId));
}
public CustomTypeMutableLiveData<RoomInfo> getRoomInfo() {
return roomInfo;
}
public CustomTypeMutableLiveData<Me> getMe() {
return me;
}
public CustomTypeMutableLiveData<Producers> getProducers() {
return producers;
}
public CustomTypeMutableLiveData<Peers> getPeers() {
return peers;
}
public CustomTypeMutableLiveData<Consumers> getConsumers() {
return consumers;
}
public MutableLiveData<Notify> getNotify() {
return notify;
}
For any help, reach out to us on Slack. We are available 24*7 at: Huddle01 Community.
Last updated
Was this helpful?