> ## Documentation Index
> Fetch the complete documentation index at: https://www.cometchat.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Participant List

> CometChat Calling SDK v5 - Custom Participant List for Android

Build a custom participant list UI that displays real-time participant information with full control over layout and interactions. This guide demonstrates how to hide the default participant list and create your own using participant events and actions.

## Overview

The SDK provides participant data through events, allowing you to build custom UIs for:

* Participant roster with search and filtering
* Custom participant cards with role badges or metadata
* Moderation dashboards with quick access to controls
* Attendance tracking and engagement monitoring

## Prerequisites

* CometChat Calls SDK installed and initialized
* Active call session (see [Join Session](/calls/android/join-session))
* Basic understanding of RecyclerView and adapters

***

## Step 1: Hide Default Participant List

Configure session settings to hide the default participant list button:

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    val sessionSettings = CometChatCalls.SessionSettingsBuilder()
        .hideParticipantListButton(true)
        .build()
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    SessionSettings sessionSettings = new CometChatCalls.SessionSettingsBuilder()
        .hideParticipantListButton(true)
        .build();
    ```
  </Tab>
</Tabs>

***

## Step 2: Create Participant List Layout

Create a layout with RecyclerView for displaying participants:

<Accordion title="activity_call.xml">
  ```xml theme={null}
  <?xml version="1.0" encoding="utf-8"?>
  <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="match_parent"
      android:layout_height="match_parent">

      <!-- Call View Container -->
      <FrameLayout
          android:id="@+id/callContainer"
          android:layout_width="match_parent"
          android:layout_height="match_parent" />

      <!-- Custom Participant List Panel -->
      <LinearLayout
          android:id="@+id/participantPanel"
          android:layout_width="300dp"
          android:layout_height="match_parent"
          android:layout_alignParentEnd="true"
          android:background="#F5F5F5"
          android:orientation="vertical"
          android:padding="16dp"
          android:visibility="gone">

          <!-- Header -->
          <LinearLayout
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:orientation="horizontal"
              android:paddingBottom="16dp">

              <TextView
                  android:id="@+id/participantCount"
                  android:layout_width="0dp"
                  android:layout_height="wrap_content"
                  android:layout_weight="1"
                  android:text="Participants (0)"
                  android:textColor="#000000"
                  android:textSize="18sp"
                  android:textStyle="bold" />

              <ImageButton
                  android:id="@+id/closeButton"
                  android:layout_width="32dp"
                  android:layout_height="32dp"
                  android:background="?attr/selectableItemBackgroundBorderless"
                  android:contentDescription="Close"
                  android:src="@android:drawable/ic_menu_close_clear_cancel" />
          </LinearLayout>

          <!-- Search Bar -->
          <EditText
              android:id="@+id/searchInput"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:hint="Search participants..."
              android:padding="12dp"
              android:background="@android:color/white"
              android:layout_marginBottom="16dp" />

          <!-- Participant List -->
          <androidx.recyclerview.widget.RecyclerView
              android:id="@+id/participantRecyclerView"
              android:layout_width="match_parent"
              android:layout_height="0dp"
              android:layout_weight="1" />
      </LinearLayout>

      <!-- Toggle Button -->
      <com.google.android.material.floatingactionbutton.FloatingActionButton
          android:id="@+id/toggleParticipantListButton"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_alignParentEnd="true"
          android:layout_alignParentBottom="true"
          android:layout_margin="16dp"
          android:contentDescription="Participants"
          android:src="@android:drawable/ic_menu_agenda" />
  </RelativeLayout>
  ```
</Accordion>

<Accordion title="item_participant.xml">
  ```xml theme={null}
  <?xml version="1.0" encoding="utf-8"?>
  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:orientation="horizontal"
      android:padding="12dp"
      android:background="?attr/selectableItemBackground">

      <!-- Avatar -->
      <ImageView
          android:id="@+id/participantAvatar"
          android:layout_width="40dp"
          android:layout_height="40dp"
          android:layout_marginEnd="12dp"
          android:contentDescription="Avatar" />

      <!-- Info -->
      <LinearLayout
          android:layout_width="0dp"
          android:layout_height="wrap_content"
          android:layout_weight="1"
          android:orientation="vertical">

          <TextView
              android:id="@+id/participantName"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:textColor="#000000"
              android:textSize="16sp"
              android:textStyle="bold" />

          <LinearLayout
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:orientation="horizontal">

              <TextView
                  android:id="@+id/statusIndicator"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:textSize="12sp"
                  android:textColor="#666666" />
          </LinearLayout>
      </LinearLayout>

      <!-- Action Buttons -->
      <LinearLayout
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:orientation="horizontal">

          <ImageButton
              android:id="@+id/muteButton"
              android:layout_width="32dp"
              android:layout_height="32dp"
              android:background="?attr/selectableItemBackgroundBorderless"
              android:contentDescription="Mute"
              android:src="@android:drawable/ic_lock_silent_mode" />

          <ImageButton
              android:id="@+id/videoPauseButton"
              android:layout_width="32dp"
              android:layout_height="32dp"
              android:background="?attr/selectableItemBackgroundBorderless"
              android:contentDescription="Pause Video"
              android:src="@android:drawable/ic_menu_camera" />

          <ImageButton
              android:id="@+id/pinButton"
              android:layout_width="32dp"
              android:layout_height="32dp"
              android:background="?attr/selectableItemBackgroundBorderless"
              android:contentDescription="Pin"
              android:src="@android:drawable/btn_star" />
      </LinearLayout>
  </LinearLayout>
  ```
</Accordion>

***

## Step 3: Create Participant Adapter

Build a RecyclerView adapter to display participant data:

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    class ParticipantAdapter(
        private val onMuteClick: (Participant) -> Unit,
        private val onPauseVideoClick: (Participant) -> Unit,
        private val onPinClick: (Participant) -> Unit
    ) : RecyclerView.Adapter<ParticipantAdapter.ViewHolder>() {

        private var participants = listOf<Participant>()
        private var filteredParticipants = listOf<Participant>()

        class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
            val avatar: ImageView = view.findViewById(R.id.participantAvatar)
            val name: TextView = view.findViewById(R.id.participantName)
            val status: TextView = view.findViewById(R.id.statusIndicator)
            val muteButton: ImageButton = view.findViewById(R.id.muteButton)
            val videoPauseButton: ImageButton = view.findViewById(R.id.videoPauseButton)
            val pinButton: ImageButton = view.findViewById(R.id.pinButton)
        }

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
            val view = LayoutInflater.from(parent.context)
                .inflate(R.layout.item_participant, parent, false)
            return ViewHolder(view)
        }

        override fun onBindViewHolder(holder: ViewHolder, position: Int) {
            val participant = filteredParticipants[position]

            // Set name
            holder.name.text = participant.name

            // Load avatar (use your image loading library)
            // Glide.with(holder.avatar).load(participant.avatar).into(holder.avatar)

            // Build status text
            val statusParts = mutableListOf<String>()
            if (participant.isAudioMuted) statusParts.add("🔇 Muted")
            if (participant.isVideoPaused) statusParts.add("📹 Video Off")
            if (participant.isPresenting) statusParts.add("🖥️ Presenting")
            if (participant.raisedHandTimestamp > 0) statusParts.add("✋ Hand Raised")
            if (participant.isPinned) statusParts.add("📌 Pinned")
            
            holder.status.text = if (statusParts.isEmpty()) "Active" else statusParts.joinToString(" • ")

            // Action buttons
            holder.muteButton.setOnClickListener { onMuteClick(participant) }
            holder.videoPauseButton.setOnClickListener { onPauseVideoClick(participant) }
            holder.pinButton.setOnClickListener { onPinClick(participant) }

            // Update button states
            holder.muteButton.alpha = if (participant.isAudioMuted) 0.5f else 1.0f
            holder.videoPauseButton.alpha = if (participant.isVideoPaused) 0.5f else 1.0f
            holder.pinButton.alpha = if (participant.isPinned) 1.0f else 0.5f
        }

        override fun getItemCount() = filteredParticipants.size

        fun updateParticipants(newParticipants: List<Participant>) {
            participants = newParticipants
            filteredParticipants = newParticipants
            notifyDataSetChanged()
        }

        fun filter(query: String) {
            filteredParticipants = if (query.isEmpty()) {
                participants
            } else {
                participants.filter { 
                    it.name.contains(query, ignoreCase = true) 
                }
            }
            notifyDataSetChanged()
        }
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    public class ParticipantAdapter extends RecyclerView.Adapter<ParticipantAdapter.ViewHolder> {

        private List<Participant> participants = new ArrayList<>();
        private List<Participant> filteredParticipants = new ArrayList<>();
        private final OnActionListener listener;

        public interface OnActionListener {
            void onMuteClick(Participant participant);
            void onPauseVideoClick(Participant participant);
            void onPinClick(Participant participant);
        }

        public ParticipantAdapter(OnActionListener listener) {
            this.listener = listener;
        }

        static class ViewHolder extends RecyclerView.ViewHolder {
            ImageView avatar;
            TextView name;
            TextView status;
            ImageButton muteButton;
            ImageButton videoPauseButton;
            ImageButton pinButton;

            ViewHolder(View view) {
                super(view);
                avatar = view.findViewById(R.id.participantAvatar);
                name = view.findViewById(R.id.participantName);
                status = view.findViewById(R.id.statusIndicator);
                muteButton = view.findViewById(R.id.muteButton);
                videoPauseButton = view.findViewById(R.id.videoPauseButton);
                pinButton = view.findViewById(R.id.pinButton);
            }
        }

        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.item_participant, parent, false);
            return new ViewHolder(view);
        }

        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
            Participant participant = filteredParticipants.get(position);

            // Set name
            holder.name.setText(participant.getName());

            // Load avatar (use your image loading library)
            // Glide.with(holder.avatar).load(participant.getAvatar()).into(holder.avatar);

            // Build status text
            List<String> statusParts = new ArrayList<>();
            if (participant.isAudioMuted()) statusParts.add("🔇 Muted");
            if (participant.isVideoPaused()) statusParts.add("📹 Video Off");
            if (participant.isPresenting()) statusParts.add("🖥️ Presenting");
            if (participant.getRaisedHandTimestamp() > 0) statusParts.add("✋ Hand Raised");
            if (participant.isPinned()) statusParts.add("📌 Pinned");

            holder.status.setText(statusParts.isEmpty() ? "Active" : String.join(" • ", statusParts));

            // Action buttons
            holder.muteButton.setOnClickListener(v -> listener.onMuteClick(participant));
            holder.videoPauseButton.setOnClickListener(v -> listener.onPauseVideoClick(participant));
            holder.pinButton.setOnClickListener(v -> listener.onPinClick(participant));

            // Update button states
            holder.muteButton.setAlpha(participant.isAudioMuted() ? 0.5f : 1.0f);
            holder.videoPauseButton.setAlpha(participant.isVideoPaused() ? 0.5f : 1.0f);
            holder.pinButton.setAlpha(participant.isPinned() ? 1.0f : 0.5f);
        }

        @Override
        public int getItemCount() {
            return filteredParticipants.size();
        }

        public void updateParticipants(List<Participant> newParticipants) {
            participants = new ArrayList<>(newParticipants);
            filteredParticipants = new ArrayList<>(newParticipants);
            notifyDataSetChanged();
        }

        public void filter(String query) {
            if (query.isEmpty()) {
                filteredParticipants = new ArrayList<>(participants);
            } else {
                filteredParticipants = new ArrayList<>();
                for (Participant p : participants) {
                    if (p.getName().toLowerCase().contains(query.toLowerCase())) {
                        filteredParticipants.add(p);
                    }
                }
            }
            notifyDataSetChanged();
        }
    }
    ```
  </Tab>
</Tabs>

***

## Step 4: Implement Participant Events

Listen for participant updates and handle actions in your Activity:

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    class CallActivity : AppCompatActivity() {

        private lateinit var participantAdapter: ParticipantAdapter
        private lateinit var callSession: CallSession
        private var isParticipantPanelVisible = false

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_call)

            callSession = CallSession.getInstance()

            // Setup RecyclerView
            val recyclerView = findViewById<RecyclerView>(R.id.participantRecyclerView)
            recyclerView.layoutManager = LinearLayoutManager(this)
            
            participantAdapter = ParticipantAdapter(
                onMuteClick = { participant ->
                    callSession.muteParticipant(participant.uid)
                },
                onPauseVideoClick = { participant ->
                    callSession.pauseParticipantVideo(participant.uid)
                },
                onPinClick = { participant ->
                    if (participant.isPinned) {
                        callSession.unPinParticipant()
                    } else {
                        callSession.pinParticipant(participant.uid)
                    }
                }
            )
            recyclerView.adapter = participantAdapter

            // Setup search
            val searchInput = findViewById<EditText>(R.id.searchInput)
            searchInput.addTextChangedListener(object : TextWatcher {
                override fun afterTextChanged(s: Editable?) {
                    participantAdapter.filter(s.toString())
                }
                override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
                override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
            })

            // Setup toggle button
            findViewById<FloatingActionButton>(R.id.toggleParticipantListButton).setOnClickListener {
                toggleParticipantPanel()
            }

            // Setup close button
            findViewById<ImageButton>(R.id.closeButton).setOnClickListener {
                toggleParticipantPanel()
            }

            // Listen for participant events
            setupParticipantListener()
        }

        private fun setupParticipantListener() {
            callSession.addParticipantEventListener(this, object : ParticipantEventListener() {
                override fun onParticipantListChanged(participants: List<Participant>) {
                    runOnUiThread {
                        participantAdapter.updateParticipants(participants)
                        updateParticipantCount(participants.size)
                    }
                }

                override fun onParticipantJoined(participant: Participant) {
                    Log.d(TAG, "${participant.name} joined")
                }

                override fun onParticipantLeft(participant: Participant) {
                    Log.d(TAG, "${participant.name} left")
                }

                override fun onParticipantAudioMuted(participant: Participant) {
                    // Adapter will update automatically via onParticipantListChanged
                }

                override fun onParticipantAudioUnmuted(participant: Participant) {
                    // Adapter will update automatically via onParticipantListChanged
                }

                override fun onParticipantVideoPaused(participant: Participant) {
                    // Adapter will update automatically via onParticipantListChanged
                }

                override fun onParticipantVideoResumed(participant: Participant) {
                    // Adapter will update automatically via onParticipantListChanged
                }

                override fun onParticipantHandRaised(participant: Participant) {
                    // Adapter will update automatically via onParticipantListChanged
                }

                override fun onParticipantHandLowered(participant: Participant) {
                    // Adapter will update automatically via onParticipantListChanged
                }
            })
        }

        private fun toggleParticipantPanel() {
            val panel = findViewById<LinearLayout>(R.id.participantPanel)
            isParticipantPanelVisible = !isParticipantPanelVisible
            panel.visibility = if (isParticipantPanelVisible) View.VISIBLE else View.GONE
        }

        private fun updateParticipantCount(count: Int) {
            findViewById<TextView>(R.id.participantCount).text = "Participants ($count)"
        }

        companion object {
            private const val TAG = "CallActivity"
        }
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    public class CallActivity extends AppCompatActivity {

        private ParticipantAdapter participantAdapter;
        private CallSession callSession;
        private boolean isParticipantPanelVisible = false;
        private static final String TAG = "CallActivity";

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_call);

            callSession = CallSession.getInstance();

            // Setup RecyclerView
            RecyclerView recyclerView = findViewById(R.id.participantRecyclerView);
            recyclerView.setLayoutManager(new LinearLayoutManager(this));

            participantAdapter = new ParticipantAdapter(new ParticipantAdapter.OnActionListener() {
                @Override
                public void onMuteClick(Participant participant) {
                    callSession.muteParticipant(participant.getUid());
                }

                @Override
                public void onPauseVideoClick(Participant participant) {
                    callSession.pauseParticipantVideo(participant.getUid());
                }

                @Override
                public void onPinClick(Participant participant) {
                    if (participant.isPinned()) {
                        callSession.unPinParticipant();
                    } else {
                        callSession.pinParticipant(participant.getUid());
                    }
                }
            });
            recyclerView.setAdapter(participantAdapter);

            // Setup search
            EditText searchInput = findViewById(R.id.searchInput);
            searchInput.addTextChangedListener(new TextWatcher() {
                @Override
                public void afterTextChanged(Editable s) {
                    participantAdapter.filter(s.toString());
                }

                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {}
            });

            // Setup toggle button
            findViewById(R.id.toggleParticipantListButton).setOnClickListener(v -> toggleParticipantPanel());

            // Setup close button
            findViewById(R.id.closeButton).setOnClickListener(v -> toggleParticipantPanel());

            // Listen for participant events
            setupParticipantListener();
        }

        private void setupParticipantListener() {
            callSession.addParticipantEventListener(this, new ParticipantEventListener() {
                @Override
                public void onParticipantListChanged(List<Participant> participants) {
                    runOnUiThread(() -> {
                        participantAdapter.updateParticipants(participants);
                        updateParticipantCount(participants.size());
                    });
                }

                @Override
                public void onParticipantJoined(Participant participant) {
                    Log.d(TAG, participant.getName() + " joined");
                }

                @Override
                public void onParticipantLeft(Participant participant) {
                    Log.d(TAG, participant.getName() + " left");
                }

                @Override
                public void onParticipantAudioMuted(Participant participant) {
                    // Adapter will update automatically via onParticipantListChanged
                }

                @Override
                public void onParticipantAudioUnmuted(Participant participant) {
                    // Adapter will update automatically via onParticipantListChanged
                }

                @Override
                public void onParticipantVideoPaused(Participant participant) {
                    // Adapter will update automatically via onParticipantListChanged
                }

                @Override
                public void onParticipantVideoResumed(Participant participant) {
                    // Adapter will update automatically via onParticipantListChanged
                }

                @Override
                public void onParticipantHandRaised(Participant participant) {
                    // Adapter will update automatically via onParticipantListChanged
                }

                @Override
                public void onParticipantHandLowered(Participant participant) {
                    // Adapter will update automatically via onParticipantListChanged
                }
            });
        }

        private void toggleParticipantPanel() {
            LinearLayout panel = findViewById(R.id.participantPanel);
            isParticipantPanelVisible = !isParticipantPanelVisible;
            panel.setVisibility(isParticipantPanelVisible ? View.VISIBLE : View.GONE);
        }

        private void updateParticipantCount(int count) {
            TextView countView = findViewById(R.id.participantCount);
            countView.setText("Participants (" + count + ")");
        }
    }
    ```
  </Tab>
</Tabs>

***

## Complete Example

Here's the full implementation with all components:

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    class CallActivity : AppCompatActivity() {

        private lateinit var participantAdapter: ParticipantAdapter
        private lateinit var callSession: CallSession
        private var isParticipantPanelVisible = false

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_call)

            callSession = CallSession.getInstance()
            setupUI()
            setupParticipantListener()
            joinCall()
        }

        private fun setupUI() {
            // Setup RecyclerView
            val recyclerView = findViewById<RecyclerView>(R.id.participantRecyclerView)
            recyclerView.layoutManager = LinearLayoutManager(this)
            
            participantAdapter = ParticipantAdapter(
                onMuteClick = { callSession.muteParticipant(it.uid) },
                onPauseVideoClick = { callSession.pauseParticipantVideo(it.uid) },
                onPinClick = { 
                    if (it.isPinned) callSession.unPinParticipant() 
                    else callSession.pinParticipant(it.uid)
                }
            )
            recyclerView.adapter = participantAdapter

            // Setup search
            findViewById<EditText>(R.id.searchInput).addTextChangedListener(object : TextWatcher {
                override fun afterTextChanged(s: Editable?) {
                    participantAdapter.filter(s.toString())
                }
                override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
                override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
            })

            // Setup buttons
            findViewById<FloatingActionButton>(R.id.toggleParticipantListButton)
                .setOnClickListener { toggleParticipantPanel() }
            findViewById<ImageButton>(R.id.closeButton)
                .setOnClickListener { toggleParticipantPanel() }
        }

        private fun setupParticipantListener() {
            callSession.addParticipantEventListener(this, object : ParticipantEventListener() {
                override fun onParticipantListChanged(participants: List<Participant>) {
                    runOnUiThread {
                        participantAdapter.updateParticipants(participants)
                        findViewById<TextView>(R.id.participantCount).text = 
                            "Participants (${participants.size})"
                    }
                }

                override fun onParticipantJoined(participant: Participant) {
                    Toast.makeText(this@CallActivity, 
                        "${participant.name} joined", Toast.LENGTH_SHORT).show()
                }

                override fun onParticipantLeft(participant: Participant) {
                    Toast.makeText(this@CallActivity, 
                        "${participant.name} left", Toast.LENGTH_SHORT).show()
                }
            })
        }

        private fun joinCall() {
            val sessionSettings = CometChatCalls.SessionSettingsBuilder()
                .hideParticipantListButton(true)
                .setTitle("Team Meeting")
                .build()

            val callContainer = findViewById<FrameLayout>(R.id.callContainer)

            CometChatCalls.joinSession(
                sessionId = "SESSION_ID",
                sessionSettings = sessionSettings,
                view = callContainer,
                context = this,
                listener = object : CometChatCalls.CallbackListener<Void>() {
                    override fun onSuccess(p0: Void?) {
                        Log.d(TAG, "Joined call successfully")
                    }

                    override fun onError(exception: CometChatException) {
                        Log.e(TAG, "Failed to join: ${exception.message}")
                        Toast.makeText(this@CallActivity, 
                            "Failed to join call", Toast.LENGTH_SHORT).show()
                    }
                }
            )
        }

        private fun toggleParticipantPanel() {
            val panel = findViewById<LinearLayout>(R.id.participantPanel)
            isParticipantPanelVisible = !isParticipantPanelVisible
            panel.visibility = if (isParticipantPanelVisible) View.VISIBLE else View.GONE
        }

        companion object {
            private const val TAG = "CallActivity"
        }
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    public class CallActivity extends AppCompatActivity {

        private ParticipantAdapter participantAdapter;
        private CallSession callSession;
        private boolean isParticipantPanelVisible = false;
        private static final String TAG = "CallActivity";

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_call);

            callSession = CallSession.getInstance();
            setupUI();
            setupParticipantListener();
            joinCall();
        }

        private void setupUI() {
            // Setup RecyclerView
            RecyclerView recyclerView = findViewById(R.id.participantRecyclerView);
            recyclerView.setLayoutManager(new LinearLayoutManager(this));

            participantAdapter = new ParticipantAdapter(new ParticipantAdapter.OnActionListener() {
                @Override
                public void onMuteClick(Participant participant) {
                    callSession.muteParticipant(participant.getUid());
                }

                @Override
                public void onPauseVideoClick(Participant participant) {
                    callSession.pauseParticipantVideo(participant.getUid());
                }

                @Override
                public void onPinClick(Participant participant) {
                    if (participant.isPinned()) {
                        callSession.unPinParticipant();
                    } else {
                        callSession.pinParticipant(participant.getUid());
                    }
                }
            });
            recyclerView.setAdapter(participantAdapter);

            // Setup search
            EditText searchInput = findViewById(R.id.searchInput);
            searchInput.addTextChangedListener(new TextWatcher() {
                @Override
                public void afterTextChanged(Editable s) {
                    participantAdapter.filter(s.toString());
                }

                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {}
            });

            // Setup buttons
            findViewById(R.id.toggleParticipantListButton).setOnClickListener(v -> 
                toggleParticipantPanel());
            findViewById(R.id.closeButton).setOnClickListener(v -> 
                toggleParticipantPanel());
        }

        private void setupParticipantListener() {
            callSession.addParticipantEventListener(this, new ParticipantEventListener() {
                @Override
                public void onParticipantListChanged(List<Participant> participants) {
                    runOnUiThread(() -> {
                        participantAdapter.updateParticipants(participants);
                        TextView countView = findViewById(R.id.participantCount);
                        countView.setText("Participants (" + participants.size() + ")");
                    });
                }

                @Override
                public void onParticipantJoined(Participant participant) {
                    Toast.makeText(CallActivity.this, 
                        participant.getName() + " joined", Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onParticipantLeft(Participant participant) {
                    Toast.makeText(CallActivity.this, 
                        participant.getName() + " left", Toast.LENGTH_SHORT).show();
                }
            });
        }

        private void joinCall() {
            SessionSettings sessionSettings = new CometChatCalls.SessionSettingsBuilder()
                    .hideParticipantListButton(true)
                    .setTitle("Team Meeting")
                    .build();

            FrameLayout callContainer = findViewById(R.id.callContainer);

            CometChatCalls.joinSession(
                    "SESSION_ID",
                    sessionSettings,
                    callContainer,
                    this,
                    new CometChatCalls.CallbackListener<Void>() {
                        @Override
                        public void onSuccess(Void unused) {
                            Log.d(TAG, "Joined call successfully");
                        }

                        @Override
                        public void onError(CometChatException e) {
                            Log.e(TAG, "Failed to join: " + e.getMessage());
                            Toast.makeText(CallActivity.this, 
                                "Failed to join call", Toast.LENGTH_SHORT).show();
                        }
                    }
            );
        }

        private void toggleParticipantPanel() {
            LinearLayout panel = findViewById(R.id.participantPanel);
            isParticipantPanelVisible = !isParticipantPanelVisible;
            panel.setVisibility(isParticipantPanelVisible ? View.VISIBLE : View.GONE);
        }
    }
    ```
  </Tab>
</Tabs>

<Accordion title="Participant Object Reference">
  | Property              | Type    | Description                                      |
  | --------------------- | ------- | ------------------------------------------------ |
  | `uid`                 | String  | Unique identifier (CometChat user ID)            |
  | `name`                | String  | Display name                                     |
  | `avatar`              | String  | URL of avatar image                              |
  | `pid`                 | String  | Participant ID for this call session             |
  | `role`                | String  | Role in the call                                 |
  | `audioMuted`          | Boolean | Whether audio is muted                           |
  | `videoPaused`         | Boolean | Whether video is paused                          |
  | `isPinned`            | Boolean | Whether pinned in layout                         |
  | `isPresenting`        | Boolean | Whether screen sharing                           |
  | `raisedHandTimestamp` | Long    | Timestamp when hand was raised (0 if not raised) |
</Accordion>
