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!