Receive a screen share
When another participant starts, pauses, resumes, or stops sharing, the Video SDK for Android fires onUserShareStatusChanged on your ZoomVideoSDKDelegate. Render the incoming share by attaching a ZoomVideoSDKVideoView to your layout and subscribing it to the share canvas.
Confirmation that the local user's own share started successfully comes from the return value of startShareScreen and the onFailedToStartShare callback.
Add a share view to your layout
Place a ZoomVideoSDKVideoView in the layout you want to render shares into.
<FrameLayout
android:id="@+id/share_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
You'll attach a ZoomVideoSDKVideoView to this container at runtime when a share starts, and remove it when the share stops.
Listen for share status changes
The callback receives the user whose share state changed and a ZoomVideoSDKShareAction describing the change.
private val shareViews = mutableMapOf<String, ZoomVideoSDKVideoView>()
override fun onUserShareStatusChanged(
shareHelper: ZoomVideoSDKShareHelper,
userInfo: ZoomVideoSDKUser,
shareAction: ZoomVideoSDKShareAction
) {
val container = findViewById<FrameLayout>(R.id.share_container)
val userId = userInfo.userID
when (shareAction.shareStatus) {
ZoomVideoSDKShareStatus.ZoomVideoSDKShareStatus_Start -> {
val videoView = ZoomVideoSDKVideoView(this)
container.addView(videoView)
shareViews[userId] = videoView
shareAction.shareCanvas.subscribe(
videoView,
ZoomVideoSDKVideoAspect.ZoomVideoSDKVideoAspect_Original,
ZoomVideoSDKVideoResolution.ZoomVideoSDKResolution_Auto
)
}
ZoomVideoSDKShareStatus.ZoomVideoSDKShareStatus_Stop -> {
shareViews.remove(userId)?.let {
shareAction.shareCanvas.unSubscribe(it)
container.removeView(it)
}
}
ZoomVideoSDKShareStatus.ZoomVideoSDKShareStatus_Pause,
ZoomVideoSDKShareStatus.ZoomVideoSDKShareStatus_Resume,
ZoomVideoSDKShareStatus.ZoomVideoSDKShareStatus_None -> {
// No subscription change — see the table below.
}
}
}
private final Map<String, ZoomVideoSDKVideoView> shareViews = new HashMap<>();
@Override
public void onUserShareStatusChanged(
ZoomVideoSDKShareHelper shareHelper,
ZoomVideoSDKUser userInfo,
ZoomVideoSDKShareAction shareAction
) {
FrameLayout container = findViewById(R.id.share_container);
String userId = userInfo.getUserID();
switch (shareAction.getShareStatus()) {
case ZoomVideoSDKShareStatus_Start: {
ZoomVideoSDKVideoView videoView = new ZoomVideoSDKVideoView(this);
container.addView(videoView);
shareViews.put(userId, videoView);
shareAction.getShareCanvas().subscribe(
videoView,
ZoomVideoSDKVideoAspect.ZoomVideoSDKVideoAspect_Original,
ZoomVideoSDKVideoResolution.ZoomVideoSDKResolution_Auto
);
break;
}
case ZoomVideoSDKShareStatus_Stop: {
ZoomVideoSDKVideoView videoView = shareViews.remove(userId);
if (videoView != null) {
shareAction.getShareCanvas().unSubscribe(videoView);
container.removeView(videoView);
}
break;
}
case ZoomVideoSDKShareStatus_Pause:
case ZoomVideoSDKShareStatus_Resume:
case ZoomVideoSDKShareStatus_None:
// No subscription change — see the table below.
break;
}
}
Tracking views in a per-user map makes it easy to attach and detach them as users start and stop sharing, and to find them later in the lifecycle callbacks covered below.
Share status values
The onUserShareStatusChanged callback reports the share state as a ZoomVideoSDKShareStatus value. Each value tells you whether to subscribe the view, keep it, or tear it down.
| Status | When it fires | What to do |
|---|---|---|
ZoomVideoSDKShareStatus_Start | The user began sharing. | Subscribe the share canvas to a ZoomVideoSDKVideoView and add the view to your layout. |
ZoomVideoSDKShareStatus_Pause | The user paused the share. | Optionally dim or overlay the view. The last frame stays on screen. Keep the subscription. |
ZoomVideoSDKShareStatus_Resume | The user resumed a paused share. | Clear any pause overlay you applied. Keep the subscription. |
ZoomVideoSDKShareStatus_Stop | The user stopped sharing, either programmatically or via the system Media Projection notification. | Unsubscribe the view and remove it from your layout. |
ZoomVideoSDKShareStatus_None | There is no active share for this user. | No action needed. This is typically the initial state. |
Aspect mode and resolution
The subscribe call takes two enums that control how the share renders:
ZoomVideoSDKVideoAspect_Originalkeeps the source aspect ratio with letterboxing if the view doesn't match. This is the safest default and what this topic uses.ZoomVideoSDKVideoAspect_Full_Filledfills the view, cropping if the aspect ratios disagree.ZoomVideoSDKVideoAspect_LetterBoxandZoomVideoSDKVideoAspect_PanAndScangive finer control. See the video best practices for guidance on choosing an aspect mode.
ZoomVideoSDKResolution_Auto lets the SDK pick the streaming resolution based on view size and network conditions. Force a specific resolution only if you have a clear reason. Pinning low when you have screen real estate hurts quality, and pinning high when you don't wastes bandwidth.
React to dimension changes
When the sharer resizes their window, rotates their device, or otherwise changes the content dimensions, the SDK fires onShareContentSizeChanged. Read the new dimensions from the share action and re-layout your container if the aspect ratio is now different.
override fun onShareContentSizeChanged(shareAction: ZoomVideoSDKShareAction) {
val size = shareAction.shareSourceContentSize // ZoomVideoSDKViewSize
// Resize your container or the share view to match the new aspect.
}
@Override
public void onShareContentSizeChanged(ZoomVideoSDKShareAction shareAction) {
ZoomVideoSDKViewSize size = shareAction.getShareSourceContentSize();
// Resize your container or the share view to match the new aspect.
}
Handle subscription failures
If a share canvas subscription can't be established (for example, the share has already stopped between callback and subscribe, or the SDK hits a resource limit), the delegate fires onShareCanvasSubscribeFail. Surface the error to the user, remove the orphaned view from your layout, and consider retrying once.
override fun onShareCanvasSubscribeFail(
failReason: ZoomVideoSDKVideoSubscribeFailReason,
user: ZoomVideoSDKUser,
view: ZoomVideoSDKVideoView
) {
// Remove the view from your layout and surface the failure.
}
@Override
public void onShareCanvasSubscribeFail(
ZoomVideoSDKVideoSubscribeFailReason failReason,
ZoomVideoSDKUser user,
ZoomVideoSDKVideoView view
) {
// Remove the view from your layout and surface the failure.
}
Identify the share source
A share may be a screen, a camera, or a pure-audio stream. Read getShareType() on the action to identify which.
when (shareAction.shareType) {
ZoomVideoSDKShareType.ZoomVideoSDKShareType_Normal -> {
// Screen, application window, or external source.
}
ZoomVideoSDKShareType.ZoomVideoSDKShareType_Camera -> {
// The user is sharing a camera as content.
}
ZoomVideoSDKShareType.ZoomVideoSDKShareType_PureAudio -> {
// Audio-only share — no video frames, no canvas to subscribe.
}
ZoomVideoSDKShareType.ZoomVideoSDKShareType_None -> {}
}
switch (shareAction.getShareType()) {
case ZoomVideoSDKShareType_Normal:
// Screen, application window, or external source.
break;
case ZoomVideoSDKShareType_Camera:
// The user is sharing a camera as content.
break;
case ZoomVideoSDKShareType_PureAudio:
// Audio-only share — no video frames, no canvas to subscribe.
break;
case ZoomVideoSDKShareType_None:
break;
}
Skip the canvas subscription when shareType is ZoomVideoSDKShareType_PureAudio. There are no frames to render.
The SDK also fires onShareContentChanged when a sharer switches between source types (for example, from camera share to screen share) without stopping the share. Treat it as a signal to refresh anything you cached based on share type.
Unsubscribe when your view goes away
Activity rotation, navigation, or tearing down a video tile all destroy ZoomVideoSDKVideoView instances. Always unSubscribe from the share canvas before the view is detached. Otherwise the SDK keeps holding a reference and you leak memory and bandwidth.
override fun onDestroy() {
val container = findViewById<FrameLayout>(R.id.share_container)
shareViews.forEach { (userId, view) ->
// Find the user and unsubscribe from their share canvas.
ZoomVideoSDK.getInstance().session.remoteUsers
.firstOrNull { it.userID == userId }
?.shareActionList
?.firstOrNull()
?.shareCanvas
?.unSubscribe(view)
container.removeView(view)
}
shareViews.clear()
super.onDestroy()
}
@Override
protected void onDestroy() {
FrameLayout container = findViewById(R.id.share_container);
for (Map.Entry<String, ZoomVideoSDKVideoView> entry : shareViews.entrySet()) {
ZoomVideoSDKUser user = findUserById(entry.getKey());
if (user != null) {
List<ZoomVideoSDKShareAction> actions = user.getShareActionList();
if (!actions.isEmpty()) {
actions.get(0).getShareCanvas().unSubscribe(entry.getValue());
}
}
container.removeView(entry.getValue());
}
shareViews.clear();
super.onDestroy();
}
For the same reason, prefer keeping share-related state in a ViewModel so configuration changes (such as device rotation) don't tear down the share UI alongside the Activity. For the pattern, see the Lifecycle in the video best practices.
Check whether anyone is sharing
Outside of the callback, you can also query whether any other participant is currently sharing, useful when joining a session in progress.
val otherSharing = ZoomVideoSDK.getInstance().shareHelper.isOtherSharing
boolean otherSharing = ZoomVideoSDK.getInstance().getShareHelper().isOtherSharing();
If multiple users may be sharing at the same time, see Handle Multiple Screen Shares for how to pick which share to subscribe to. To draw on a share you're viewing, see Annotation.