From 1e8b0f1dc8fa3b375af1928a22f1ff48f3326f80 Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Wed, 8 Apr 2026 12:36:52 +0200 Subject: [PATCH 1/4] chore: support custom android title --- .../src/main/java/io/getstream/rn/callingx/CallService.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/react-native-callingx/android/src/main/java/io/getstream/rn/callingx/CallService.kt b/packages/react-native-callingx/android/src/main/java/io/getstream/rn/callingx/CallService.kt index 811a62a149..9eb0755164 100644 --- a/packages/react-native-callingx/android/src/main/java/io/getstream/rn/callingx/CallService.kt +++ b/packages/react-native-callingx/android/src/main/java/io/getstream/rn/callingx/CallService.kt @@ -105,7 +105,10 @@ class CallService : Service(), CallRepository.Listener { return } - val callName = data["created_by_display_name"].orEmpty() + val createdName = data["created_by_display_name"].orEmpty() + val displayName = data["call_display_name"].orEmpty() + val defaultCallText = "Unknown Caller" + val isVideo = data["video"] == "true" CallRegistrationStore.trackCallRegistration(callCid, null) @@ -115,7 +118,7 @@ class CallService : Service(), CallRepository.Listener { action = ACTION_INCOMING_CALL putExtra(EXTRA_CALL_ID, callCid) putExtra(EXTRA_URI, callCid.toUri()) - putExtra(EXTRA_NAME, callName) + putExtra(EXTRA_NAME, displayName.ifEmpty { createdName.ifEmpty { defaultCallText } }) putExtra(EXTRA_IS_VIDEO, isVideo) } From bd37cd0247001a08b03425be98eacc3182f69c0d Mon Sep 17 00:00:00 2001 From: Artem Grintsevich Date: Wed, 8 Apr 2026 15:13:12 +0200 Subject: [PATCH 2/4] chore: made displaying custom display name consistent --- .../main/java/io/getstream/rn/callingx/CallService.kt | 5 +++-- .../react-native-sdk/ios/StreamVideoReactNative.m | 10 +++++----- .../hooks/push/useCallingExpWithCallingStateEffect.ts | 7 +++++-- .../src/utils/internal/callingx/callingx.ts | 11 +++++++---- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/packages/react-native-callingx/android/src/main/java/io/getstream/rn/callingx/CallService.kt b/packages/react-native-callingx/android/src/main/java/io/getstream/rn/callingx/CallService.kt index ea37c0e532..e8fe460f06 100644 --- a/packages/react-native-callingx/android/src/main/java/io/getstream/rn/callingx/CallService.kt +++ b/packages/react-native-callingx/android/src/main/java/io/getstream/rn/callingx/CallService.kt @@ -48,6 +48,8 @@ class CallService : Service(), CallRepository.Listener { companion object { private const val TAG = "[Callingx] CallService" + internal const val DEFAULT_DISPLAY_NAME = "Unknown Caller" + internal const val EXTRA_CALL_ID = "extra_call_id" internal const val EXTRA_NAME = "extra_name" internal const val EXTRA_URI = "extra_uri" @@ -108,7 +110,6 @@ class CallService : Service(), CallRepository.Listener { val createdById = data["created_by_id"] ?: callCid val createdName = data["created_by_display_name"].orEmpty() val displayName = data["call_display_name"].orEmpty() - val defaultCallText = "Unknown Caller" val isVideo = data["video"] == "true" @@ -119,7 +120,7 @@ class CallService : Service(), CallRepository.Listener { action = ACTION_INCOMING_CALL putExtra(EXTRA_CALL_ID, callCid) putExtra(EXTRA_URI, createdById.toUri()) - putExtra(EXTRA_NAME, displayName.ifEmpty { createdName.ifEmpty { defaultCallText } }) + putExtra(EXTRA_NAME, displayName.ifEmpty { createdName.ifEmpty { DEFAULT_DISPLAY_NAME } }) putExtra(EXTRA_IS_VIDEO, isVideo) } diff --git a/packages/react-native-sdk/ios/StreamVideoReactNative.m b/packages/react-native-sdk/ios/StreamVideoReactNative.m index 033f7dd29c..0a1ac71aaa 100644 --- a/packages/react-native-sdk/ios/StreamVideoReactNative.m +++ b/packages/react-native-sdk/ios/StreamVideoReactNative.m @@ -25,6 +25,8 @@ NSNotificationName const kBroadcastStartedNotification = @"iOS_BroadcastStarted"; NSNotificationName const kBroadcastStoppedNotification = @"iOS_BroadcastStopped"; +static NSString *const DEFAULT_DISPLAY_NAME = @"Unknown Caller"; + static dispatch_queue_t _dictionaryQueue = nil; void broadcastNotificationCallback(CFNotificationCenterRef center, @@ -165,11 +167,8 @@ +(void)didReceiveIncomingPush:(PKPushPayload *)payload forType:(NSString *)type return; } - NSString *callDisplayName = streamPayload[@"call_display_name"]; - NSString *createdByDisplayName = streamPayload[@"created_by_display_name"]; - NSString *createdCallerName = callDisplayName.length > 0 ? callDisplayName : createdByDisplayName; NSString *callCid = streamPayload[@"call_cid"]; - if (!createdCallerName || !callCid) { + if (!callCid) { #if DEBUG NSLog(@"[StreamVideoReactNative][didReceiveIncomingPush] Missing required fields: created_by_display_name or call_cid"); #endif @@ -207,10 +206,11 @@ +(void)reportNewIncomingCall:(NSDictionary *)streamPayload forType:(NSString *)t NSString *callCid = streamPayload[@"call_cid"]; NSString *createdById = streamPayload[@"created_by_id"]; + NSString *handle = createdById.length > 0 ? createdById : callCid; NSString *callDisplayName = streamPayload[@"call_display_name"]; NSString *createdByDisplayName = streamPayload[@"created_by_display_name"]; NSString *createdCallerName = callDisplayName.length > 0 ? callDisplayName : createdByDisplayName; - NSString *localizedCallerName = createdCallerName.length > 0 ? createdCallerName : @"Unknown Caller"; + NSString *localizedCallerName = createdCallerName.length > 0 ? createdCallerName : DEFAULT_DISPLAY_NAME; NSString *videoIncluded = streamPayload[@"video"]; BOOL hasVideo = [videoIncluded isEqualToString:@"false"] ? NO : YES; NSString *handleType = @"generic"; diff --git a/packages/react-native-sdk/src/hooks/push/useCallingExpWithCallingStateEffect.ts b/packages/react-native-sdk/src/hooks/push/useCallingExpWithCallingStateEffect.ts index 9aa614d937..d8429dcb72 100644 --- a/packages/react-native-sdk/src/hooks/push/useCallingExpWithCallingStateEffect.ts +++ b/packages/react-native-sdk/src/hooks/push/useCallingExpWithCallingStateEffect.ts @@ -21,13 +21,16 @@ export const useCallingExpWithCallingStateEffect = () => { const activeCallCid = activeCall?.cid; const createdByUserId = activeCall?.state.createdBy?.id; + const callCustomDisplayName = activeCall?.state.custom?.display_name; const currentUserId = activeCall?.currentUserId; const isIncoming = (activeCall?.ringing && !activeCall?.isCreatedByMe) || false; const callDisplayName = useMemo( - () => getCallDisplayName(callMembers, participants, currentUserId), - [callMembers, participants, currentUserId], + () => + callCustomDisplayName ?? + getCallDisplayName(callMembers, participants, currentUserId), + [callMembers, participants, currentUserId, callCustomDisplayName], ); useEffect(() => { diff --git a/packages/react-native-sdk/src/utils/internal/callingx/callingx.ts b/packages/react-native-sdk/src/utils/internal/callingx/callingx.ts index 62573ca635..26bc244a8a 100644 --- a/packages/react-native-sdk/src/utils/internal/callingx/callingx.ts +++ b/packages/react-native-sdk/src/utils/internal/callingx/callingx.ts @@ -54,10 +54,13 @@ export function getCallDisplayName( } function getCallDisplayNameFromCall(call: Call): string { - return getCallDisplayName( - call.state.members, - call.state.participants, - call.currentUserId, + return ( + call.state.custom?.display_name ?? + getCallDisplayName( + call.state.members, + call.state.participants, + call.currentUserId, + ) ); } From bea3c89bc1fda720965c4eecf1a78059cbc2f7f3 Mon Sep 17 00:00:00 2001 From: Artem Grintsevich Date: Wed, 8 Apr 2026 15:19:50 +0200 Subject: [PATCH 3/4] chore: use handle field --- packages/react-native-sdk/ios/StreamVideoReactNative.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-native-sdk/ios/StreamVideoReactNative.m b/packages/react-native-sdk/ios/StreamVideoReactNative.m index 0a1ac71aaa..7708557a2e 100644 --- a/packages/react-native-sdk/ios/StreamVideoReactNative.m +++ b/packages/react-native-sdk/ios/StreamVideoReactNative.m @@ -170,7 +170,7 @@ +(void)didReceiveIncomingPush:(PKPushPayload *)payload forType:(NSString *)type NSString *callCid = streamPayload[@"call_cid"]; if (!callCid) { #if DEBUG - NSLog(@"[StreamVideoReactNative][didReceiveIncomingPush] Missing required fields: created_by_display_name or call_cid"); + NSLog(@"[StreamVideoReactNative][didReceiveIncomingPush] Missing required field: call_cid"); #endif if (completion) { completion(); @@ -225,7 +225,7 @@ +(void)reportNewIncomingCall:(NSDictionary *)streamPayload forType:(NSString *)t [invocation setTarget:callingxClass]; [invocation setSelector:selector]; [invocation setArgument:&callCid atIndex:2]; - [invocation setArgument:&createdById atIndex:3]; + [invocation setArgument:&handle atIndex:3]; [invocation setArgument:&handleType atIndex:4]; [invocation setArgument:&hasVideo atIndex:5]; [invocation setArgument:&localizedCallerName atIndex:6]; From 05cd272a14037b1923903b134bd139155905d2c2 Mon Sep 17 00:00:00 2001 From: Artem Grintsevich Date: Wed, 8 Apr 2026 18:11:04 +0200 Subject: [PATCH 4/4] chore: updated handle fallback values --- .../src/main/java/io/getstream/rn/callingx/CallService.kt | 7 ++++--- packages/react-native-sdk/ios/StreamVideoReactNative.m | 4 ++-- .../src/hooks/push/useCallingExpWithCallingStateEffect.ts | 2 +- .../src/utils/internal/callingx/callingx.ts | 6 +++--- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/react-native-callingx/android/src/main/java/io/getstream/rn/callingx/CallService.kt b/packages/react-native-callingx/android/src/main/java/io/getstream/rn/callingx/CallService.kt index e8fe460f06..27778022c3 100644 --- a/packages/react-native-callingx/android/src/main/java/io/getstream/rn/callingx/CallService.kt +++ b/packages/react-native-callingx/android/src/main/java/io/getstream/rn/callingx/CallService.kt @@ -107,9 +107,10 @@ class CallService : Service(), CallRepository.Listener { return } - val createdById = data["created_by_id"] ?: callCid + val createdById = data["created_by_id"] val createdName = data["created_by_display_name"].orEmpty() val displayName = data["call_display_name"].orEmpty() + val callDisplayName = displayName.ifEmpty { createdName.ifEmpty { DEFAULT_DISPLAY_NAME } } val isVideo = data["video"] == "true" @@ -119,8 +120,8 @@ class CallService : Service(), CallRepository.Listener { Intent(context, CallService::class.java).apply { action = ACTION_INCOMING_CALL putExtra(EXTRA_CALL_ID, callCid) - putExtra(EXTRA_URI, createdById.toUri()) - putExtra(EXTRA_NAME, displayName.ifEmpty { createdName.ifEmpty { DEFAULT_DISPLAY_NAME } }) + putExtra(EXTRA_URI, createdById?.toUri() ?: callDisplayName.toUri()) + putExtra(EXTRA_NAME, callDisplayName) putExtra(EXTRA_IS_VIDEO, isVideo) } diff --git a/packages/react-native-sdk/ios/StreamVideoReactNative.m b/packages/react-native-sdk/ios/StreamVideoReactNative.m index 7708557a2e..848cee9071 100644 --- a/packages/react-native-sdk/ios/StreamVideoReactNative.m +++ b/packages/react-native-sdk/ios/StreamVideoReactNative.m @@ -205,12 +205,12 @@ +(void)reportNewIncomingCall:(NSDictionary *)streamPayload forType:(NSString *)t } NSString *callCid = streamPayload[@"call_cid"]; - NSString *createdById = streamPayload[@"created_by_id"]; - NSString *handle = createdById.length > 0 ? createdById : callCid; NSString *callDisplayName = streamPayload[@"call_display_name"]; NSString *createdByDisplayName = streamPayload[@"created_by_display_name"]; NSString *createdCallerName = callDisplayName.length > 0 ? callDisplayName : createdByDisplayName; NSString *localizedCallerName = createdCallerName.length > 0 ? createdCallerName : DEFAULT_DISPLAY_NAME; + NSString *createdById = streamPayload[@"created_by_id"]; + NSString *handle = createdById.length > 0 ? createdById : localizedCallerName; NSString *videoIncluded = streamPayload[@"video"]; BOOL hasVideo = [videoIncluded isEqualToString:@"false"] ? NO : YES; NSString *handleType = @"generic"; diff --git a/packages/react-native-sdk/src/hooks/push/useCallingExpWithCallingStateEffect.ts b/packages/react-native-sdk/src/hooks/push/useCallingExpWithCallingStateEffect.ts index d8429dcb72..2229e7baef 100644 --- a/packages/react-native-sdk/src/hooks/push/useCallingExpWithCallingStateEffect.ts +++ b/packages/react-native-sdk/src/hooks/push/useCallingExpWithCallingStateEffect.ts @@ -112,7 +112,7 @@ export const useCallingExpWithCallingStateEffect = () => { callingx.updateDisplay( activeCallCid, - createdByUserId ?? activeCallCid, + createdByUserId ?? callDisplayName, callDisplayName, isIncoming, ); diff --git a/packages/react-native-sdk/src/utils/internal/callingx/callingx.ts b/packages/react-native-sdk/src/utils/internal/callingx/callingx.ts index 26bc244a8a..37b812d0c8 100644 --- a/packages/react-native-sdk/src/utils/internal/callingx/callingx.ts +++ b/packages/react-native-sdk/src/utils/internal/callingx/callingx.ts @@ -80,7 +80,7 @@ export async function registerOutgoingCall(call: Call) { logger.debug(`registerOutgoingCall: Registering outgoing call ${call.cid}`); await CallingxModule.startCall( call.cid, // unique id for call - call.state.createdBy?.id ?? call.id, // handle for native call UI (prefer createdBy user id, fallback to call id) + call.state.createdBy?.id ?? getCallDisplayNameFromCall(call), // handle for native call UI (prefer createdBy user id, fallback to call display name) getCallDisplayNameFromCall(call), // display name for display in call screen call.state.settings?.video?.enabled ?? false, // is video call? ); @@ -117,7 +117,7 @@ export async function joinCallingxCall(call: Call, activeCalls: Call[]) { logger.debug(`joinCallingxCall: Joining call ${call.cid}`); await CallingxModule.startCall( call.cid, // unique id for call - call.state.createdBy?.id ?? call.id, // handle for native call UI (prefer createdBy user id, fallback to call id) + call.state.createdBy?.id ?? getCallDisplayNameFromCall(call), // handle for native call UI (prefer createdBy user id, fallback to call display name) getCallDisplayNameFromCall(call), // display name for display in call screen call.state.settings?.video?.enabled ?? false, // is video call? ); @@ -156,7 +156,7 @@ export async function joinCallingxCall(call: Call, activeCalls: Call[]) { // iOS early-returns with no error, Android sends the registered broadcast. await CallingxModule.displayIncomingCall( call.cid, // unique id for call - call.state.createdBy?.id ?? call.id, // handle for native call UI (prefer createdBy user id, fallback to call id) + call.state.createdBy?.id ?? getCallDisplayNameFromCall(call), // handle for native call UI (prefer createdBy user id, fallback to call display name) getCallDisplayNameFromCall(call), // display name for display in call screen call.state.settings?.video?.enabled ?? false, // is video call? );