# Core features The Video SDK for Android lets users share content with others in a session. The SDK supports three kinds of share sources: - **Screen share**: mirror the device's screen using Android's [`MediaProjectionManager`](https://developer.android.com/reference/android/media/projection/MediaProjectionManager). - **Camera share**: broadcast a camera as a content stream alongside the user's normal video, useful for document cameras or secondary perspectives. - **External source**: feed in an arbitrary frame source through the SDK's preprocessing pipe. Sharing the screen involves requesting permission, running a foreground service, and starting, stopping, and pausing a share. To broadcast a camera or external frame source instead, see [Share a camera or external source](/docs/video-sdk/android/share/share-camera-or-external-source/). To render an incoming share from another participant, see [Receive a screen share](/docs/video-sdk/android/share/receive-screen-share/). To draw on shared content, see [Annotation](/docs/video-sdk/android/share/annotation/). Sharing the device's screen takes three steps: 1. **Request screen-capture permission** from the user through Android's `MediaProjectionManager`. 2. **Start a foreground service** with the `mediaProjection` foreground service type. 3. **Call `startShareScreen`** on the `ZoomVideoSDKShareHelper`, passing the `Intent` returned by the permission flow. > **Note** > > Screen sharing relies on Android's foreground service, notification, and Media Projection APIs. Before starting, get comfortable with: > > - [Android Services](https://developer.android.com/guide/components/services) > - [Foreground services](https://developer.android.com/guide/components/foreground-services) > - [`MediaProjectionManager`](https://developer.android.com/reference/android/media/projection/MediaProjectionManager) ## Request screen-capture permission Use `ActivityResultLauncher` (the modern replacement for `startActivityForResult`) to launch the system's screen-capture permission dialog. ```kotlin private val screenCaptureLauncher = registerForActivityResult( ActivityResultContracts.StartActivityForResult() ) { result -> if (result.resultCode == Activity.RESULT_OK && result.data != null) { startScreenShare(result.data!!) } } fun onShareScreenClicked() { val manager = getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager screenCaptureLauncher.launch(manager.createScreenCaptureIntent()) } ``` ```java private final ActivityResultLauncher screenCaptureLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> { if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) { startScreenShare(result.getData()); } }); void onShareScreenClicked() { MediaProjectionManager manager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE); screenCaptureLauncher.launch(manager.createScreenCaptureIntent()); } ``` ## Run a foreground service Screen capture must run inside a foreground service. Implement a service that calls `startForeground` from its `onCreate`. ```kotlin class ScreenShareService : Service() { companion object { private const val CHANNEL_ID = "screen_share_channel" private const val NOTIFICATION_ID = 1 } override fun onCreate() { super.onCreate() val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager if (manager.getNotificationChannel(CHANNEL_ID) == null) { manager.createNotificationChannel( NotificationChannel( CHANNEL_ID, "Screen share", NotificationManager.IMPORTANCE_LOW ) ) } val notification = NotificationCompat.Builder(this, CHANNEL_ID) .setContentText("Screen share") .setOngoing(true) .setAutoCancel(false) .build() startForeground(NOTIFICATION_ID, notification) } override fun onBind(intent: Intent?): IBinder? = null } ``` ```java public class ScreenShareService extends Service { private static final String CHANNEL_ID = "screen_share_channel"; private static final int NOTIFICATION_ID = 1; @Override public void onCreate() { super.onCreate(); NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); if (manager.getNotificationChannel(CHANNEL_ID) == null) { manager.createNotificationChannel(new NotificationChannel( CHANNEL_ID, "Screen share", NotificationManager.IMPORTANCE_LOW )); } Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID) .setContentText("Screen share") .setOngoing(true) .setAutoCancel(false) .build(); startForeground(NOTIFICATION_ID, notification); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } } ``` Declare the service in `AndroidManifest.xml` with the `mediaProjection` type. ```xml ``` ### Foreground permissions Starting with Android 14, Google requires developers to [specify appropriate foreground service types in their apps](https://developer.android.com/about/versions/14/changes/fgs-types-required). The Video SDK uses these foreground service permissions. | Permission | Description | | ------------------------------------- | ---------------------------------------------------------------------------- | | `FOREGROUND_SERVICE_MICROPHONE` | Allow the capability to receive audio when the app is put in the background. | | `FOREGROUND_SERVICE_MEDIA_PLAYBACK` | Allow the capability to share audio while screen sharing. | | `FOREGROUND_SERVICE_MEDIA_PROJECTION` | Allow the capability to project the screen while screen sharing. | | `FOREGROUND_SERVICE_CONNECTED_DEVICE` | Allow the capability to use Bluetooth device as the audio source. | | `FOREGROUND_SERVICE_PHONE_CALL` | Allow the capability to use Bluetooth device for the meeting call. | The screen sharing feature in Video SDK requires foreground service. If the screen sharing feature is not included in your project, add the following code in `Androidmanifest.xml` to remove the service and permissions. Note that removing `FOREGROUND_SERVICE_MICROPHONE` permission might cause an audio issue when the application is in the background. Therefore, to ensure the audio works as expected, maintain `FOREGROUND_SERVICE_MICROPHONE` and `FOREGROUND_SERVICE_CONNECTED_DEVICE` permissions in the project and start the foreground service when joining a meeting. ```xml ``` ## Start the share After the foreground service is running, call `startShareScreen` on the `ZoomVideoSDKShareHelper`, passing the `Intent` returned from the permission flow. ```kotlin private fun startScreenShare(data: Intent) { val serviceIntent = Intent(this, ScreenShareService::class.java) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(serviceIntent) } else { startService(serviceIntent) } ZoomVideoSDK.getInstance().shareHelper.startShareScreen(data) } ``` ```java private void startScreenShare(Intent data) { Intent serviceIntent = new Intent(this, ScreenShareService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(serviceIntent); } else { startService(serviceIntent); } ZoomVideoSDK.getInstance().getShareHelper().startShareScreen(data); } ``` `startShareScreen` returns an `int`. `ZoomVideoSDKErrors.Errors_Success` (value `0`) means the share is starting; any other value is an error from [`ZoomVideoSDKErrors`](https://marketplacefront.zoom.us/sdk/custom/android/us/zoom/sdk/ZoomVideoSDKErrors.html). Common reasons a call fails: another user is sharing while multi-share is disabled, the session host has [locked sharing](/docs/video-sdk/android/share/handle-multiple-shares/#host-lock-sharing), or you're calling from outside an active session. Asynchronous failures arrive on the `ZoomVideoSDKDelegate` through `onFailedToStartShare`. Surface the error to the user and stop the foreground service if you started one. ```kotlin override fun onFailedToStartShare() { // The screen-capture session never began. Tear down the foreground service. stopService(Intent(this, ScreenShareService::class.java)) showShareError() } ``` ```java @Override public void onFailedToStartShare() { // The screen-capture session never began. Tear down the foreground service. stopService(new Intent(this, ScreenShareService.class)); showShareError(); } ``` ## Stop the share To end a share programmatically, call `stopShare`. This works for screen, camera, and external-source shares. ```kotlin ZoomVideoSDK.getInstance().shareHelper.stopShare() stopService(Intent(this, ScreenShareService::class.java)) ``` ```java ZoomVideoSDK.getInstance().getShareHelper().stopShare(); stopService(new Intent(this, ScreenShareService.class)); ``` Inside the service, the recommended Android pattern for shutting down is `stopForeground(STOP_FOREGROUND_REMOVE)` followed by `stopSelf()`. ```kotlin override fun onDestroy() { stopForeground(STOP_FOREGROUND_REMOVE) super.onDestroy() } ``` ```java @Override public void onDestroy() { stopForeground(STOP_FOREGROUND_REMOVE); super.onDestroy(); } ``` A share also stops when the user taps **Stop sharing** in the system Media Projection notification. The SDK reports both programmatic and system-initiated stops the same way: `onUserShareStatusChanged` fires with `ZoomVideoSDKShareStatus_Stop`. Tear down your foreground service from that callback so both paths converge on the same cleanup code. For the callback signature, see [Receive a screen share](/docs/video-sdk/android/share/receive-screen-share/). ## Pause and resume Pause an ongoing share without disconnecting from the screen-capture session. Viewers see a frozen frame until you resume. ```kotlin val shareHelper = ZoomVideoSDK.getInstance().shareHelper shareHelper.pauseShare() // Later: shareHelper.resumeShare() ``` ```java ZoomVideoSDKShareHelper shareHelper = ZoomVideoSDK.getInstance().getShareHelper(); shareHelper.pauseShare(); // Later: shareHelper.resumeShare(); ``` Receivers detect pause and resume through the `ZoomVideoSDKShareStatus_Pause` and `ZoomVideoSDKShareStatus_Resume` values on `onUserShareStatusChanged`. ## Share device audio To send the device's audio alongside the screen capture (so viewers hear music, video sound, or app audio), enable share device audio before or during the share. ```kotlin val shareHelper = ZoomVideoSDK.getInstance().shareHelper shareHelper.enableShareDeviceAudio(true) // Check whether device-audio capture is on. val isOn = shareHelper.isShareDeviceAudioEnabled ``` ```java ZoomVideoSDKShareHelper shareHelper = ZoomVideoSDK.getInstance().getShareHelper(); shareHelper.enableShareDeviceAudio(true); // Check whether device-audio capture is on. boolean isOn = shareHelper.isShareDeviceAudioEnabled(); ``` > **Device-audio capture requires:** > > - Android 10 (API 29) or later. > - The `RECORD_AUDIO` runtime permission. > - The `FOREGROUND_SERVICE_MEDIA_PLAYBACK` foreground service type on your share service (see [Foreground permissions](#foreground-permissions) above). > > The SDK does not capture device audio while the virtual speaker is enabled. ## Check the local share state Use the share helper's state queries to drive your UI. For example, to disable a **Share screen** button while the local user is already sharing, or while another participant is. ```kotlin val shareHelper = ZoomVideoSDK.getInstance().shareHelper // The local user is currently sharing (any share type). val sharing = shareHelper.isSharingOut // The local user is specifically sharing the screen. val sharingScreen = shareHelper.isScreenSharingOut // Some other participant is sharing. val otherSharing = shareHelper.isOtherSharing ``` ```java ZoomVideoSDKShareHelper shareHelper = ZoomVideoSDK.getInstance().getShareHelper(); boolean sharing = shareHelper.isSharingOut(); boolean sharingScreen = shareHelper.isScreenSharingOut(); boolean otherSharing = shareHelper.isOtherSharing(); ```