Skip to content

Forward the original push payload into the notification handler - #1481

Merged
aleksandar-apostolov merged 12 commits into
developfrom
feature/rahullohra/push-payload-downstream
Aug 1, 2025
Merged

Forward the original push payload into the notification handler#1481
aleksandar-apostolov merged 12 commits into
developfrom
feature/rahullohra/push-payload-downstream

Conversation

@rahul-lohra

@rahul-lohra rahul-lohra commented Jul 28, 2025

Copy link
Copy Markdown
Contributor

🎯 Goal

  1. Propagate push payload from FCM down to our Notification APIs
  2. Customizing PendingIntent Bundles

Propagate push payload from FCM down to our Notification APIs

Enhance the notification handling flow by forwarding the full push notification payload (key-value pairs) to the StreamNotificationHandler interface.
This allows client applications to access the original push payload and consume custom fields (e.g., dynamic titles, metadata) directly, which was not possible before.

🛠 Implementation details

Existing API will new extend new interface which has payload:Map<String, Any?>


// ========================================
// NEW APIs (with payload)
// ========================================

// StreamNotificationHandlerWithPayload
fun onRingingCall(callId: StreamCallId, callDisplayName: String, payload: Map<String, Any?>)
fun onMissedCall(callId: StreamCallId, callDisplayName: String, payload: Map<String, Any?>)
fun onNotification(callId: StreamCallId, callDisplayName: String, payload: Map<String, Any?>)
fun onLiveCall(callId: StreamCallId, callDisplayName: String, payload: Map<String, Any?>)

// StreamNotificationProviderWithPayload
fun getIncomingCallNotification(..., payload: Map<String, Any?>)
fun getOngoingCallNotification(..., payload: Map<String, Any?>)
fun getRingingCallNotification(..., payload: Map<String, Any?>)
fun getMissedCallNotification(..., payload: Map<String, Any?>)

// StreamNotificationBuilderInterceptorsWithPayload
fun onBuildIncomingCallNotification(..., payload: Map<String, Any?>)
fun onBuildOngoingCallNotification(..., payload: Map<String, Any?>)
fun onBuildMissedCallNotification(..., payload: Map<String, Any?>)
fun onBuildOutgoingCallNotification(..., payload: Map<String, Any?>)


// ========================================
// DEPRECATED APIs (without payload)
// ========================================

// StreamNotificationHandler
fun onRingingCall(callId: StreamCallId, callDisplayName: String)
fun onMissedCall(callId: StreamCallId, callDisplayName: String)
fun onNotification(callId: StreamCallId, callDisplayName: String)
fun onLiveCall(callId: StreamCallId, callDisplayName: String)

// StreamNotificationProvider
fun getIncomingCallNotification(..., shouldHaveContentIntent: Boolean)
fun getOngoingCallNotification(callId: StreamCallId, callDisplayName: String?, isOutgoingCall: Boolean, remoteParticipantCount: Int)
fun getRingingCallNotification(ringingState: RingingState, callId: StreamCallId, callDisplayName: String?, shouldHaveContentIntent: Boolean)
fun getMissedCallNotification(callId: StreamCallId, callDisplayName: String?)

// StreamNotificationBuilderInterceptors
fun onBuildIncomingCallNotification(...)
fun onBuildOngoingCallNotification(...)
fun onBuildMissedCallNotification(...)
fun onBuildOutgoingCallNotification(...)

Customizing PendingIntent Bundles

We’ve introduced new APIs that allow client applications to customize the Bundle attached to PendingIntents.
This enables you to:

  • Control behaviors such as "last leave" policy and other configurations.
  • Pass custom key–value pairs directly to StreamCallActivity.

Implementation Details

  • Added two new interfaces:

    • StreamIntentResolverWithPayload
    • NotificationIntentBundleResolver
      These are used internally by the Notification Handler.
  • Provided a DefaultNotificationIntentBundleResolver, which can be supplied during SDK initialization.

// ========================================
// NEW APIs (with payload)
// ========================================

// StreamIntentResolverWithPayload
fun searchIncomingCallPendingIntent(callId: StreamCallId, callDisplayName: String, payload: Map<String, Any?>): PendingIntent?
fun searchOutgoingCallPendingIntent(callId: StreamCallId, callDisplayName: String, payload: Map<String, Any?>): PendingIntent?
fun searchNotificationCallPendingIntent(callId: StreamCallId, callDisplayName: String, payload: Map<String, Any?>): PendingIntent?
fun getDefaultPendingIntent(payload: Map<String, Any?>): PendingIntent?
fun searchLiveCallPendingIntent(callId: StreamCallId, callDisplayName: String, payload: Map<String, Any?>): PendingIntent?
fun searchAcceptCallPendingIntent(callId: StreamCallId, callDisplayName: String, payload: Map<String, Any?>): PendingIntent?
fun searchRejectCallPendingIntent(callId: StreamCallId, callDisplayName: String, payload: Map<String, Any?>): PendingIntent?
fun searchEndCallPendingIntent(callId: StreamCallId, callDisplayName: String, payload: Map<String, Any?>): PendingIntent?
fun searchOngoingCallPendingIntent(callId: StreamCallId, callDisplayName: String, payload: Map<String, Any?>): PendingIntent?

// ========================================
// DEPRECATED APIs (without payload)
// ========================================

//StreamIntentResolver
fun searchIncomingCallPendingIntent(callId: StreamCallId, callDisplayName: String): PendingIntent?
fun searchOutgoingCallPendingIntent(callId: StreamCallId, callDisplayName: String): PendingIntent?
fun searchNotificationCallPendingIntent(callId: StreamCallId, callDisplayName: String): PendingIntent?
fun getDefaultPendingIntent(): PendingIntent?
fun searchLiveCallPendingIntent(callId: StreamCallId, callDisplayName: String): PendingIntent?
fun searchAcceptCallPendingIntent(callId: StreamCallId, callDisplayName: String): PendingIntent?
fun searchRejectCallPendingIntent(callId: StreamCallId, callDisplayName: String): PendingIntent?
fun searchEndCallPendingIntent(callId: StreamCallId, callDisplayName: String): PendingIntent?
fun searchOngoingCallPendingIntent(callId: StreamCallId, callDisplayName: String): PendingIntent?

// ========================================
// NEW APIs (with payload)
// ========================================
//NotificationIntentBundleResolver
fun getIncomingCallBundle(callId: StreamCallId, callDisplayName: String, payload: Map<String, Any?>): Bundle   
fun getOutgoingCallBundle(callId: StreamCallId, callDisplayName: String, payload: Map<String, Any?>): Bundle
fun getNotificationCallBundle(callId: StreamCallId, callDisplayName: String, payload: Map<String, Any?>): Bundle
fun getMissedCallBundle(callId: StreamCallId, callDisplayName: String, payload: Map<String, Any?>): Bundle
fun getDefaultBundle(payload: Map<String, Any?>): Bundle
fun getLiveCallBundle(callId: StreamCallId, callDisplayName: String, payload: Map<String, Any?>): Bundle
fun getAcceptCallBundle(callId: StreamCallId, callDisplayName: String, payload: Map<String, Any?>): Bundle
fun getRejectCallBundle(callId: StreamCallId, payload: Map<String, Any?>): Bundle
fun getEndCallPendingBundle(callId: StreamCallId, payload: Map<String, Any?>): Bundle
fun getOngoingCallBundle(callId: StreamCallId, notificationId: Int, payload: Map<String, Any?>): Bundle

Client Usage

Here is an example on how you can customise the bundle for accect and reject bundle on the incoming call
We will extend DefaultNotificationIntentBundleResolver and override getAcceptCallBundle and getRejectCallBundle

To simplify creating a base bundle for StreamCallActivity, you can use the helper method:

StreamCallActivity.callIntentBundle(...)
private fun initializeStreamVideo(context: Context): StreamVideo {        
        return StreamVideoBuilder(               
                notificationHandler = CompatibilityStreamNotificationHandler(
                    application = context.applicationContext,
                    intentResolver = DefaultStreamIntentResolver(
                        context,
                        object : DefaultNotificationIntentBundleResolver() {

                            override fun getAcceptCallBundle(
                                callId: StreamCallId,
                                notificationId: Int,
                                payload: Map<String, Any?>,
                            ): Bundle {
                                return StreamCallActivity.callIntentBundle(
                                    callId,
                                    configuration = StreamCallActivityConfiguration(
                                        closeScreenOnCallEnded = true,
                                    ),
                                    leaveWhenLastInCall = true,
                                )
                            }

                            override fun getRejectCallBundle(
                                callId: StreamCallId,
                                payload: Map<String, Any?>,
                            ): Bundle {
                                return StreamCallActivity.callIntentBundle(
                                    callId,
                                    configuration = StreamCallActivityConfiguration(
                                        closeScreenOnCallEnded = true,
                                    ),
                                    leaveWhenLastInCall = true,
                                )
                            }
                        },
                    ),
                ),
            ),        
        ).build()
    }

@rahul-lohra rahul-lohra self-assigned this Jul 28, 2025
@rahul-lohra
rahul-lohra requested a review from a team as a code owner July 28, 2025 12:39
@github-actions

github-actions Bot commented Jul 28, 2025

Copy link
Copy Markdown
Contributor

SDK Size Comparison 📏

SDK Before After Difference Status
stream-video-android-core 11.43 MB 11.43 MB 0.00 MB 🟢
stream-video-android-ui-xml 5.68 MB 5.70 MB 0.02 MB 🟢
stream-video-android-ui-compose 5.88 MB 5.88 MB 0.00 MB 🟢

@rahul-lohra
rahul-lohra marked this pull request as draft July 28, 2025 13:20
@rahul-lohra
rahul-lohra marked this pull request as ready for review July 28, 2025 13:46
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
37.1% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@aleksandar-apostolov
aleksandar-apostolov merged commit 8b2950e into develop Aug 1, 2025
10 of 11 checks passed
@aleksandar-apostolov
aleksandar-apostolov deleted the feature/rahullohra/push-payload-downstream branch August 1, 2025 08:17
@aleksandar-apostolov aleksandar-apostolov changed the title Forward push payload for custom notification handling Forward the original push payload into the notification handler Aug 1, 2025
@aleksandar-apostolov aleksandar-apostolov added the pr:new-feature Adds new functionality label Aug 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:new-feature Adds new functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants