Talk to us
Talk to us
menu

How to Integrate Screen Sharing into an Android Video Chat App

How to Integrate Screen Sharing into an Android Video Chat App

Screen sharing transforms ordinary video calls into collaborative experiences—letting users present slides, demo apps, or solve problems in real time. By adding this feature, your Android video chat app becomes more useful for remote teams, educators, and support agents alike. In this guide, you’ll learn how to integrate screen sharing into Android video chat apps step by step. We’ll show you how to capture screen content, stream it to other users, and manage permissions effectively, with ready-to-use code examples to get you started quickly.

How to Integrate Screen Sharing into Android Video Calls

Android phones can capture screen content using the MediaProjection API. But sending that video to many people at once is much harder. You need systems that compress video, handle poor internet connections, and work across different devices. Building all this yourself takes many months of difficult coding.

ZEGOCLOUD handles all this complexity for you. We’ll build an Android video calling app that uses it’s video calling SDK for screen sharing. First we’ll create basic video calling, then add screen capture on top.

This implementation captures your device screen, streams it to other participants, and manages permissions properly. The complete code lets you test everything right away.

Prerequisites

Before you start building, make sure you have these things ready:

  • A ZEGOCLOUD account – sign up at console.zegocloud.com
  • Android Studio 2020.3.1 or later installed.
  • Android SDK 25 or higher with Build-Tools 25.0.2 or later.
  • Target device running Android 5.0 (API level 21) or higher.
  • Valid AppID and AppSign from ZEGOCLOUD Console.
  • Basic understanding of Android development and permissions.

1. Create Your Android Project

Start by creating a new Android project that will serve as the foundation for video calling and screen sharing. You can skip this step if you have your app already:

  • Open Android Studio and select “File > New > Project”. Choose “Empty Activity” and configure your project: Application name: VideoCallScreenShare Package name: com.example.videocallscreenshare Language: Java Minimum SDK: API 21 (Android 5.0)

This creates the basic project structure with MainActivity.java and the necessary configuration files.

2. Configure Project Dependencies

Add ZEGOCLOUD SDK and required dependencies to enable real-time video communication.

Update app/build.gradle:

android {
    compileSdk 34

    defaultConfig {
        applicationId "com.example.videocallscreenshare"
        minSdk 21
        targetSdk 34
        versionCode 1
        versionName "1.0"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'com.google.android.material:material:1.9.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'

    // ZEGOCLOUD Express SDK for video calling and screen sharing
    implementation 'im.zego:express-video:3.14.5'
}

Update settings.gradle (Project level):

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        // ZEGOCLOUD Maven repository
        maven { url 'https://storage.zego.im/maven' }
    }
}

These dependencies provide the ZEGOCLOUD Express SDK that handles video calling, audio processing, and screen capture functionality automatically.

3. Add Required Permissions

Configure your app to access camera, microphone, and screen recording capabilities that are essential for video calls and screen sharing. Update app/src/main/AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <!-- Basic video call permissions -->
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.BLUETOOTH" />

    <!-- Screen sharing permissions -->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION"/>
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

    <!-- Hardware features -->
    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />
    <uses-feature android:glEsVersion="0x00020000" android:required="true" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/Theme.VideoCallScreenShare"
        tools:targetApi="31">

        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

These permissions allow your app to access camera and microphone for video calls, plus the special foreground service permissions needed for screen recording on modern Android versions.

4. Create the User Interface Layout

Design a clean interface that provides controls for video calling and screen sharing functionality.

Create app/src/main/res/layout/activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#000000"
    tools:context=".MainActivity">

    <!-- Local video preview (camera or screen share) -->
    <TextureView
        android:id="@+id/localVideoView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true" />

    <!-- Remote participant video view -->
    <TextureView
        android:id="@+id/remoteVideoView"
        android:layout_width="150dp"
        android:layout_height="200dp"
        android:layout_alignParentTop="true"
        android:layout_alignParentEnd="true"
        android:layout_margin="16dp"
        android:background="#333333"
        android:visibility="gone" />

    <!-- Status indicator for screen sharing -->
    <TextView
        android:id="@+id/tvScreenShareStatus"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_margin="16dp"
        android:background="#80000000"
        android:padding="8dp"
        android:text="Screen Sharing Active"
        android:textColor="#FFFFFF"
        android:textSize="14sp"
        android:visibility="gone" />

    <!-- Control buttons -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_margin="20dp"
        android:gravity="center"
        android:orientation="horizontal">

        <com.google.android.material.button.MaterialButton
            android:id="@+id/btnStartCall"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="8dp"
            android:backgroundTint="#4CAF50"
            android:text="Start Call"
            android:textColor="#FFFFFF" />

        <com.google.android.material.button.MaterialButton
            android:id="@+id/btnScreenShare"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="8dp"
            android:backgroundTint="#2196F3"
            android:enabled="false"
            android:text="Share Screen"
            android:textColor="#FFFFFF" />

        <com.google.android.material.button.MaterialButton
            android:id="@+id/btnEndCall"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="8dp"
            android:backgroundTint="#F44336"
            android:enabled="false"
            android:text="End Call"
            android:textColor="#FFFFFF" />

    </LinearLayout>

    <!-- Room ID input (for testing) -->
    <com.google.android.material.textfield.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@id/btnStartCall"
        android:layout_margin="20dp"
        android:layout_marginBottom="80dp">

        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/etRoomId"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Enter Room ID"
            android:text="demo_room_123"
            android:textColor="#FFFFFF"
            android:textColorHint="#CCCCCC" />

    </com.google.android.material.textfield.TextInputLayout>

</RelativeLayout>

This layout provides a full-screen video preview with floating controls for call management and screen sharing. The remote video appears as a small overlay window.

5. Create the Main Activity Class

Implement the core functionality that handles video calling, user interactions, and screen sharing coordination. Create/Update app/src/main/java/com/example/videocallscreenshare/MainActivity.java:

package com.example.videocallscreenshare;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.media.projection.MediaProjectionManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.TextureView;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import org.json.JSONObject;

import java.util.ArrayList;

import im.zego.zegoexpress.ZegoExpressEngine;
import im.zego.zegoexpress.callback.IZegoEventHandler;
import im.zego.zegoexpress.constants.ZegoAudioChannel;
import im.zego.zegoexpress.constants.ZegoAudioSampleRate;
import im.zego.zegoexpress.constants.ZegoAudioSourceType;
import im.zego.zegoexpress.constants.ZegoPublishChannel;
import im.zego.zegoexpress.constants.ZegoScenario;
import im.zego.zegoexpress.constants.ZegoScreenCaptureExceptionType;
import im.zego.zegoexpress.constants.ZegoUpdateType;
import im.zego.zegoexpress.constants.ZegoVideoSourceType;
import im.zego.zegoexpress.entity.ZegoCanvas;
import im.zego.zegoexpress.entity.ZegoEngineProfile;
import im.zego.zegoexpress.entity.ZegoRoomConfig;
import im.zego.zegoexpress.entity.ZegoScreenCaptureConfig;
import im.zego.zegoexpress.entity.ZegoStream;
import im.zego.zegoexpress.entity.ZegoUser;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "VideoCallScreenShare";

    // ZEGOCLOUD credentials - Replace with your actual values
    private static final long APP_ID = 1234567890L; // Your App ID
    private static final String APP_SIGN = "your_app_sign_here"; // Your App Sign

    // Request codes for permissions
    private static final int PERMISSION_REQUEST_CODE = 101;
    private static final int SCREEN_CAPTURE_REQUEST_CODE = 1001;

    // ZEGOCLOUD engine instance
    private ZegoExpressEngine engine;

    // UI elements
    private TextureView localVideoView;
    private TextureView remoteVideoView;
    private TextView screenShareStatus;
    private Button btnStartCall;
    private Button btnScreenShare;
    private Button btnEndCall;
    private EditText etRoomId;

    // Call state variables
    private boolean isInCall = false;
    private boolean isScreenSharing = false;
    private String currentRoomID = "";
    private String currentUserID = "";
    private String currentStreamID = "";

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

        // Initialize user ID with timestamp for uniqueness
        currentUserID = "user_" + System.currentTimeMillis();

        initializeViews();
        requestNecessaryPermissions();
        initializeZegoEngine();
        setupButtonListeners();

        Log.d(TAG, "MainActivity created with user ID: " + currentUserID);
    }

    /**
     * Initialize all UI components and set up references
     */
    private void initializeViews() {
        localVideoView = findViewById(R.id.localVideoView);
        remoteVideoView = findViewById(R.id.remoteVideoView);
        screenShareStatus = findViewById(R.id.tvScreenShareStatus);
        btnStartCall = findViewById(R.id.btnStartCall);
        btnScreenShare = findViewById(R.id.btnScreenShare);
        btnEndCall = findViewById(R.id.btnEndCall);
        etRoomId = findViewById(R.id.etRoomId);

        // Set initial UI state
        updateButtonStates();
    }

    /**
     * Request camera and microphone permissions required for video calling
     */
    private void requestNecessaryPermissions() {
        String[] requiredPermissions = {
            Manifest.permission.CAMERA,
            Manifest.permission.RECORD_AUDIO
        };

        ArrayList<String> permissionsToRequest = new ArrayList<>();

        // Check which permissions are not granted
        for (String permission : requiredPermissions) {
            if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
                permissionsToRequest.add(permission);
            }
        }

        // Request missing permissions
        if (!permissionsToRequest.isEmpty()) {
            ActivityCompat.requestPermissions(this, 
                permissionsToRequest.toArray(new String[0]), 
                PERMISSION_REQUEST_CODE);
        }
    }
}

This creates the main activity structure with proper initialization, permission handling, and UI setup. The class manages the overall state of video calling and screen sharing.

6. Initialize ZEGOCLOUD Engine

Set up the ZEGOCLOUD Express SDK engine that handles all real-time communication functionality.

Add to MainActivity.java (continuing from previous section):

/**
     * Initialize ZEGOCLOUD Express SDK with app credentials and event handlers
     */

    private void initializeZegoEngine() {
        // Create engine profile with your app credentials
        ZegoEngineProfile profile = new ZegoEngineProfile();
        profile.appID = APP_ID;
        profile.appSign = APP_SIGN;
        profile.scenario = ZegoScenario.DEFAULT; // Use default scenario for video calls
        profile.application = getApplication();

        // Create the engine instance
        engine = ZegoExpressEngine.createEngine(profile, null);

        // Set up event handlers for real-time communication events
        setupZegoEventHandlers();

        Log.d(TAG, "ZEGOCLOUD engine initialized successfully");
    }

    /**
     * Configure event handlers to respond to video call and screen sharing events
     */
    private void setupZegoEventHandlers() {
        engine.setEventHandler(new IZegoEventHandler() {

            /**
             * Called when new video streams are available or removed from the room
             */
            @Override
            public void onRoomStreamUpdate(String roomID, ZegoUpdateType updateType, 
                                         ArrayList<ZegoStream> streamList, JSONObject extendedData) {
                super.onRoomStreamUpdate(roomID, updateType, streamList, extendedData);

                runOnUiThread(() -> {
                    if (updateType == ZegoUpdateType.ADD) {
                        // New stream available - start playing it
                        for (ZegoStream stream : streamList) {
                            Log.d(TAG, "New stream detected: " + stream.streamID);
                            startPlayingRemoteStream(stream.streamID);
                        }
                    } else {
                        // Stream removed - stop playing it
                        for (ZegoStream stream : streamList) {
                            Log.d(TAG, "Stream removed: " + stream.streamID);
                            stopPlayingRemoteStream(stream.streamID);
                        }
                    }
                });
            }

            /**
             * Called when room connection state changes
             */
            @Override
            public void onRoomStateChanged(String roomID, ZegoRoomStateChangedReason reason, 
                                         int errorCode, JSONObject extendedData) {
                super.onRoomStateChanged(roomID, reason, errorCode, extendedData);

                runOnUiThread(() -> {
                    Log.d(TAG, "Room state changed: " + reason + ", error: " + errorCode);

                    if (errorCode != 0) {
                        showToast("Room connection error: " + errorCode);
                        handleCallFailure();
                    }
                });
            }

            /**
             * Called when screen capture starts successfully
             */
            @Override
            public void onScreenCaptureStart() {
                super.onScreenCaptureStart();

                runOnUiThread(() -> {
                    Log.d(TAG, "Screen capture started successfully");
                    isScreenSharing = true;
                    screenShareStatus.setVisibility(View.VISIBLE);
                    updateButtonStates();
                    showToast("Screen sharing started");
                });
            }

            /**
             * Called when screen capture encounters an error
             */
            @Override
            public void onScreenCaptureExceptionOccurred(ZegoScreenCaptureExceptionType exceptionType) {
                super.onScreenCaptureExceptionOccurred(exceptionType);

                runOnUiThread(() -> {
                    Log.e(TAG, "Screen capture error: " + exceptionType);
                    handleScreenSharingError(exceptionType);
                    stopScreenSharing();
                });
            }
        });
    }

The event handler system above automatically responds to real-time communication events, managing stream updates, connection changes, and screen sharing status changes.

7. Implement Video Call Functions

Add the fundamental video calling capabilities that provide the foundation for screen sharing.

Add to MainActivity.java (continuing):

 /**
     * Set up click listeners for all control buttons
     */
    private void setupButtonListeners() {
        btnStartCall.setOnClickListener(v -> {
            String roomId = etRoomId.getText().toString().trim();
            if (roomId.isEmpty()) {
                showToast("Please enter a room ID");
                return;
            }
            startVideoCall(roomId);
        });

        btnScreenShare.setOnClickListener(v -> {
            if (!isInCall) {
                showToast("Start a video call first");
                return;
            }

            if (!isScreenSharing) {
                requestScreenCapturePermission();
            } else {
                stopScreenSharing();
            }
        });

        btnEndCall.setOnClickListener(v -> endVideoCall());
    }

    /**
     * Start a video call by joining a room and publishing camera stream
     */
    private void startVideoCall(String roomId) {
        currentRoomID = roomId;

        // Create user object with unique ID
        ZegoUser user = new ZegoUser(currentUserID, currentUserID);

        // Configure room settings
        ZegoRoomConfig roomConfig = new ZegoRoomConfig();
        roomConfig.isUserStatusNotify = true; // Enable user join/leave notifications

        Log.d(TAG, "Attempting to join room: " + roomId);

        // Join the video call room
        engine.loginRoom(roomId, user, roomConfig, (errorCode, extendedData) -> {
            runOnUiThread(() -> {
                if (errorCode == 0) {
                    Log.d(TAG, "Successfully joined room: " + roomId);
                    isInCall = true;

                    // Start local camera preview and publishing
                    startLocalPreview();
                    startPublishingCameraStream();

                    updateButtonStates();
                    showToast("Video call started");
                } else {
                    Log.e(TAG, "Failed to join room: " + errorCode);
                    showToast("Failed to join call: " + errorCode);
                    handleCallFailure();
                }
            });
        });
    }

    /**
     * Start local camera preview in the main video view
     */
    private void startLocalPreview() {
        ZegoCanvas localCanvas = new ZegoCanvas(localVideoView);
        engine.startPreview(localCanvas);
        Log.d(TAG, "Local camera preview started");
    }

    /**
     * Publish camera stream to other participants in the room
     */
    private void startPublishingCameraStream() {
        currentStreamID = "camera_" + currentUserID + "_" + System.currentTimeMillis();
        engine.startPublishingStream(currentStreamID);
        Log.d(TAG, "Publishing camera stream: " + currentStreamID);
    }

    /**
     * Start playing a remote participant's video stream
     */
    private void startPlayingRemoteStream(String streamID) {
        remoteVideoView.setVisibility(View.VISIBLE);
        ZegoCanvas remoteCanvas = new ZegoCanvas(remoteVideoView);
        engine.startPlayingStream(streamID, remoteCanvas);
        Log.d(TAG, "Started playing remote stream: " + streamID);
    }

    /**
     * Stop playing a remote participant's video stream
     */
    private void stopPlayingRemoteStream(String streamID) {
        engine.stopPlayingStream(streamID);
        remoteVideoView.setVisibility(View.GONE);
        Log.d(TAG, "Stopped playing remote stream: " + streamID);
    }

    /**
     * End the current video call and clean up resources
     */
    private void endVideoCall() {
        Log.d(TAG, "Ending video call");

        // Stop screen sharing if active
        if (isScreenSharing) {
            stopScreenSharing();
        }

        // Stop local preview and publishing
        engine.stopPreview();
        engine.stopPublishingStream();

        // Leave the room
        engine.logoutRoom(currentRoomID);

        // Update state and UI
        isInCall = false;
        currentRoomID = "";
        currentStreamID = "";

        // Hide remote video view
        remoteVideoView.setVisibility(View.GONE);

        updateButtonStates();
        showToast("Video call ended");
    }

    /**
     * Handle call failure scenarios
     */
    private void handleCallFailure() {
        isInCall = false;
        updateButtonStates();
    }

These functions provide complete video calling functionality, from joining rooms to managing local and remote video streams.

8. Implement Screen Sharing Functionality

Add the screen capture capabilities that allow users to share their device screen during video calls.

Add to MainActivity.java (continuing):

 /**
     * Request permission to capture screen content
    */

    private void requestScreenCapturePermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            MediaProjectionManager manager = (MediaProjectionManager) 
                getSystemService(Context.MEDIA_PROJECTION_SERVICE);

            Intent permissionIntent = manager.createScreenCaptureIntent();
            startActivityForResult(permissionIntent, SCREEN_CAPTURE_REQUEST_CODE);

            Log.d(TAG, "Requesting screen capture permission");
        } else {
            showToast("Screen sharing requires Android 5.0 or higher");
        }
    }

    /**
     * Handle the result of screen capture permission request
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == SCREEN_CAPTURE_REQUEST_CODE) {
            if (resultCode == Activity.RESULT_OK) {
                Log.d(TAG, "Screen capture permission granted");
                startScreenSharing();
            } else {
                Log.d(TAG, "Screen capture permission denied");
                showToast("Screen recording permission is required for screen sharing");
            }
        }
    }

    /**
     * Start screen sharing by switching from camera to screen capture
     */
    private void startScreenSharing() {
        Log.d(TAG, "Starting screen sharing");

        // Switch video source from camera to screen capture
        engine.setVideoSource(ZegoVideoSourceType.SCREEN_CAPTURE, ZegoPublishChannel.MAIN);

        // Optionally capture system audio along with screen
        engine.setAudioSource(ZegoAudioSourceType.SCREEN_CAPTURE, ZegoPublishChannel.MAIN);

        // Configure screen capture settings
        ZegoScreenCaptureConfig config = new ZegoScreenCaptureConfig();
        config.captureVideo = true; // Capture screen video
        config.captureAudio = true; // Capture system audio
        config.audioParam.sampleRate = ZegoAudioSampleRate.ZEGO_AUDIO_SAMPLE_RATE_44K;
        config.audioParam.channel = ZegoAudioChannel.STEREO;

        // Start screen capture with configuration
        engine.startScreenCapture(config);

        // Update stream to share screen content instead of camera
        engine.stopPublishingStream();
        currentStreamID = "screen_" + currentUserID + "_" + System.currentTimeMillis();
        engine.startPublishingStream(currentStreamID);

        Log.d(TAG, "Screen sharing configuration applied");
    }

    /**
     * Stop screen sharing and return to camera view
     */
    private void stopScreenSharing() {
        Log.d(TAG, "Stopping screen sharing");

        // Stop screen capture
        engine.stopScreenCapture();

        // Switch back to camera sources
        engine.setVideoSource(ZegoVideoSourceType.CAMERA, ZegoPublishChannel.MAIN);
        engine.setAudioSource(ZegoAudioSourceType.MICROPHONE, ZegoPublishChannel.MAIN);

        // Update state
        isScreenSharing = false;
        screenShareStatus.setVisibility(View.GONE);

        // Resume camera streaming if still in call
        if (isInCall) {
            engine.stopPublishingStream();
            startLocalPreview();
            startPublishingCameraStream();
        }

        updateButtonStates();
        showToast("Screen sharing stopped");
    }

    /**
     * Handle different types of screen sharing errors
     */
    private void handleScreenSharingError(ZegoScreenCaptureExceptionType errorType) {
        String message = "Screen sharing failed";

        switch (errorType) {
            case ZEGO_SCREEN_CAPTURE_EXCEPTION_TYPE_AUTH_FAILED:
                message = "Permission denied for screen recording";
                break;
            case ZEGO_SCREEN_CAPTURE_EXCEPTION_TYPE_SYSTEM_NOT_SUPPORT:
                message = "Device does not support screen recording";
                break;
            case ZEGO_SCREEN_CAPTURE_EXCEPTION_TYPE_FOREGROUND_SERVICE_FAILED:
                message = "Unable to start background service for screen recording";
                break;
            case ZEGO_SCREEN_CAPTURE_EXCEPTION_TYPE_WINDOW_CAPTURE_NOT_SUPPORT:
                message = "Window capture not supported on this device";
                break;
            default:
                message = "Screen sharing encountered an unexpected error";
                break;
        }

        Log.e(TAG, "Screen sharing error: " + message);
        showToast(message);
    }

This screen sharing implementation provides complete functionality for capturing device screens, handling permissions properly, and managing the transition between camera and screen content.

9. Add UI State Management and Utilities

Implement helper functions that manage button states, show user feedback, and handle app lifecycle events. Add to MainActivity.java (final section):

/**
     * Update button enabled/disabled states based on current call and sharing status
    */

    private void updateButtonStates() {
        runOnUiThread(() -> {
            btnStartCall.setEnabled(!isInCall);
            btnStartCall.setText(isInCall ? "Call Active" : "Start Call");

            btnScreenShare.setEnabled(isInCall);
            btnScreenShare.setText(isScreenSharing ? "Stop Sharing" : "Share Screen");

            btnEndCall.setEnabled(isInCall);

            // Update room ID input
            etRoomId.setEnabled(!isInCall);
        });
    }

    /**
     * Show toast message to user
     */
    private void showToast(String message) {
        runOnUiThread(() -> {
            Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();
        });
    }

    /**
     * Handle permission request results
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if (requestCode == PERMISSION_REQUEST_CODE) {
            boolean allPermissionsGranted = true;

            for (int result : grantResults) {
                if (result != PackageManager.PERMISSION_GRANTED) {
                    allPermissionsGranted = false;
                    break;
                }
            }

            if (allPermissionsGranted) {
                Log.d(TAG, "All required permissions granted");
                showToast("Permissions granted - ready for video calls");
            } else {
                Log.w(TAG, "Some permissions denied");
                showToast("Camera and microphone permissions are required for video calls");
            }
        }
    }

    /**
     * Handle back button press with confirmation for active sessions
     */
    @Override
    public void onBackPressed() {
        if (isInCall || isScreenSharing) {
            new AlertDialog.Builder(this)
                .setTitle("End Session")
                .setMessage("Do you want to end the current video call?")
                .setPositiveButton("End Call", (dialog, which) -> {
                    endVideoCall();
                    super.onBackPressed();
                })
                .setNegativeButton("Cancel", null)
                .show();
        } else {
            super.onBackPressed();
        }
    }

    /**
     * Clean up resources when activity is destroyed
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();

        Log.d(TAG, "Activity being destroyed - cleaning up resources");

        // End any active calls
        if (isInCall) {
            endVideoCall();
        }

        // Destroy ZEGOCLOUD engine and release resources
        if (engine != null) {
            ZegoExpressEngine.destroyEngine(null);
            engine = null;
        }
    }

    /**
     * Handle app going to background (screen sharing continues)
     */
    @Override
    protected void onPause() {
        super.onPause();
        if (isScreenSharing) {
            Log.d(TAG, "App paused - screen sharing continues in background");
        }
    }

    /**
     * Handle app returning to foreground
     */
    @Override
    protected void onResume() {
        super.onResume();
        if (isScreenSharing) {
            Log.d(TAG, "App resumed - screen sharing still active");
        }
    }
}

This completes the MainActivity implementation with proper state management, lifecycle handling, and user interaction feedback.

Install and open the app on two Android devices. Start a video call, then tap “Share Screen” and grant permission. Open different apps to verify screen content is captured.

Conclusion

Screen sharing is now working in your Android app. Users can show their screens during video calls with just a few taps. The MediaProjection API captures everything smoothly, and ZEGOCLOUD streams it to other participants without delays.

Your app handles permissions correctly, switches between camera and screen modes, and cleans up resources properly. The implementation works on Android 5.0 and higher, covering most devices your users have.

Test the app thoroughly, then start thinking about what screen sharing enables for your specific users. Remote support becomes instant. App demos feel natural. Team collaboration gets much easier when everyone sees the same content.

FAQ

Q1: How do I implement screen sharing in an Android video chat app?

Use Android’s MediaProjection API to capture the screen. Then, send the captured frames via WebRTC or a real-time SDK like ZEGOCLOUD. You’ll need to handle encoding, permissions, and streaming efficiently.

Q2: What permissions are required for screen sharing on Android?

You need to request the MediaProjection permission at runtime using an intent from MediaProjectionManager. The user must approve this via a system prompt before capturing starts.

Q3: Does screen sharing work on all Android versions?

Screen sharing using MediaProjection works on Android 5.0 (API 21) and above. For older versions, it’s not officially supported.

Q4: What’s the best SDK for screen sharing in Android apps?

ZEGOCLOUD, Agora, and WebRTC are popular options. ZEGOCLOUD simplifies screen sharing with built-in support for MediaProjection and real-time streaming, making it easier for developers.

Let’s Build APP Together

Start building with real-time video, voice & chat SDK for apps today!

Talk to us

Take your apps to the next level with our voice, video and chat APIs

Free Trial
  • 10,000 minutes for free
  • 4,000+ corporate clients
  • 3 Billion daily call minutes

Stay updated with us by signing up for our newsletter!

Don't miss out on important news and updates from ZEGOCLOUD!

* You may unsubscribe at any time using the unsubscribe link in the digest email. See our privacy policy for more information.