From f70627f6108df54016b65eb0e558726ae48907ef Mon Sep 17 00:00:00 2001 From: rahullohra Date: Wed, 1 Apr 2026 17:14:17 +0530 Subject: [PATCH 1/4] fix: fix locked screen incoming-call wake up notification behaviour --- .../api/stream-video-android-core.api | 8 ++- .../DefaultNotificationHandler.kt | 12 ++++ .../StreamDefaultNotificationHandler.kt | 66 +++++++++++++++++++ .../handlers/StreamNotificationHandler.kt | 13 +++- .../internal/NoOpNotificationHandler.kt | 11 ++++ .../internal/service/CallService.kt | 10 ++- 6 files changed, 116 insertions(+), 4 deletions(-) diff --git a/stream-video-android-core/api/stream-video-android-core.api b/stream-video-android-core/api/stream-video-android-core.api index 67412f54a4..1f1e8c7aed 100644 --- a/stream-video-android-core/api/stream-video-android-core.api +++ b/stream-video-android-core/api/stream-video-android-core.api @@ -13189,6 +13189,7 @@ public class io/getstream/video/android/core/notifications/DefaultNotificationHa public fun getRejectAction (Landroid/app/PendingIntent;)Landroidx/core/app/NotificationCompat$Action; public fun getRingingCallNotification (Lio/getstream/video/android/core/RingingState;Lio/getstream/video/android/model/StreamCallId;Ljava/lang/String;ZLjava/util/Map;)Landroid/app/Notification; public fun getSettingUpCallNotification ()Landroid/app/Notification; + public fun getSettingUpCallNotification (Ljava/lang/String;Lio/getstream/video/android/model/StreamCallId;)Landroid/app/Notification; public fun getStreamNotificationDispatcher ()Lio/getstream/video/android/core/notifications/dispatchers/NotificationDispatcher; public fun isInForeground ()Z public fun maybeCreateChannel (Ljava/lang/String;Landroid/content/Context;Lkotlin/jvm/functions/Function1;)V @@ -13441,6 +13442,7 @@ public class io/getstream/video/android/core/notifications/handlers/StreamDefaul public fun getOngoingCallNotification (Lio/getstream/video/android/model/StreamCallId;Ljava/lang/String;ZILjava/util/Map;)Landroid/app/Notification; public fun getRingingCallNotification (Lio/getstream/video/android/core/RingingState;Lio/getstream/video/android/model/StreamCallId;Ljava/lang/String;ZLjava/util/Map;)Landroid/app/Notification; public fun getSettingUpCallNotification ()Landroid/app/Notification; + public fun getSettingUpCallNotification (Ljava/lang/String;Lio/getstream/video/android/model/StreamCallId;)Landroid/app/Notification; public fun onCallNotificationUpdate (Lio/getstream/video/android/core/Call;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun onLiveCall (Lio/getstream/video/android/model/StreamCallId;Ljava/lang/String;Ljava/util/Map;)V public fun onMissedCall (Lio/getstream/video/android/model/StreamCallId;Ljava/lang/String;Ljava/util/Map;)V @@ -13544,7 +13546,7 @@ public abstract interface class io/getstream/video/android/core/notifications/ha public abstract fun onRingingCall (Lio/getstream/video/android/model/StreamCallId;Ljava/lang/String;Ljava/util/Map;)V } -public abstract interface class io/getstream/video/android/core/notifications/handlers/StreamNotificationProvider : io/getstream/video/android/core/notifications/handlers/StreamNotificationProviderWithPayload { +public abstract interface class io/getstream/video/android/core/notifications/handlers/StreamNotificationProvider : io/getstream/video/android/core/notifications/handlers/StreamNotificationProviderWithPayload, io/getstream/video/android/core/notifications/handlers/StreamSettingUpCallNotificationProvider { public fun getIncomingCallNotification (Landroid/app/PendingIntent;Landroid/app/PendingIntent;Landroid/app/PendingIntent;Ljava/lang/String;Z)Landroid/app/Notification; public fun getMissedCallNotification (Lio/getstream/video/android/model/StreamCallId;Ljava/lang/String;)Landroid/app/Notification; public static synthetic fun getMissedCallNotification$default (Lio/getstream/video/android/core/notifications/handlers/StreamNotificationProvider;Lio/getstream/video/android/model/StreamCallId;Ljava/lang/String;ILjava/lang/Object;)Landroid/app/Notification; @@ -13589,6 +13591,10 @@ public abstract interface class io/getstream/video/android/core/notifications/ha public abstract fun updateOutgoingCallNotification (Lio/getstream/video/android/core/Call;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; } +public abstract interface class io/getstream/video/android/core/notifications/handlers/StreamSettingUpCallNotificationProvider { + public abstract fun getSettingUpCallNotification (Ljava/lang/String;Lio/getstream/video/android/model/StreamCallId;)Landroid/app/Notification; +} + public final class io/getstream/video/android/core/notifications/internal/receivers/ToggleCameraBroadcastReceiver : android/content/BroadcastReceiver { public fun (Lkotlinx/coroutines/CoroutineScope;)V public fun onReceive (Landroid/content/Context;Landroid/content/Intent;)V diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/DefaultNotificationHandler.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/DefaultNotificationHandler.kt index 269298d31a..26fafce4db 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/DefaultNotificationHandler.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/DefaultNotificationHandler.kt @@ -244,6 +244,13 @@ public open class DefaultNotificationHandler( .build() } + @Deprecated( + "Use StreamSettingUpCallNotificationProvider.getSettingUpCallNotification(trigger,callId)", + replaceWith = ReplaceWith( + "StreamSettingUpCallNotificationProvider.getSettingUpCallNotification(trigger,callId)", + ), + level = DeprecationLevel.WARNING, + ) override fun getSettingUpCallNotification(): Notification? { val channelId = application.getString( R.string.stream_video_call_setup_notification_channel_id, @@ -277,6 +284,11 @@ public open class DefaultNotificationHandler( } } + override fun getSettingUpCallNotification( + trigger: String, + callId: StreamCallId, + ): Notification? = getSettingUpCallNotification() + override suspend fun onCallNotificationUpdate(call: Call): Notification? { coroutineScope { val localUser = StreamVideo.instance().state.user.value diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt index 50eaca304f..3eccf032f8 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt @@ -59,6 +59,7 @@ import io.getstream.video.android.core.notifications.StreamIntentResolver import io.getstream.video.android.core.notifications.dispatchers.DefaultNotificationDispatcher import io.getstream.video.android.core.notifications.dispatchers.NotificationDispatcher import io.getstream.video.android.core.notifications.extractor.DefaultNotificationContentExtractor +import io.getstream.video.android.core.notifications.internal.service.CallService.Companion.TRIGGER_INCOMING_CALL import io.getstream.video.android.core.notifications.internal.service.ServiceLauncher import io.getstream.video.android.core.utils.isAppInForeground import io.getstream.video.android.core.utils.safeCall @@ -528,6 +529,13 @@ constructor( } } + @Deprecated( + "Use StreamSettingUpCallNotificationProvider.getSettingUpCallNotification(trigger,callId)", + replaceWith = ReplaceWith( + "StreamSettingUpCallNotificationProvider.getSettingUpCallNotification(trigger,callId)", + ), + level = DeprecationLevel.WARNING, + ) override fun getSettingUpCallNotification(): Notification? { logger.d { "[getSettingUpCallNotification]" } val channelId = notificationChannels.outgoingCallChannel.id @@ -543,6 +551,64 @@ constructor( } } + override fun getSettingUpCallNotification(trigger: String, callId: StreamCallId): Notification? { + return when (trigger) { + /** + * TODO: This logic is duplicated with getIncomingCallNotificationInternal. + * Update it soon + */ + + TRIGGER_INCOMING_CALL -> { + val title = application.getString( + R.string.stream_video_call_setup_notification_title, + ) + val description = + application.getString(R.string.stream_video_call_setup_notification_description) + + val notificationChannel = when { + isAppInForeground() && hideRingingNotificationInForeground -> + notificationChannels.incomingCallLowImportanceChannel + else -> notificationChannels.incomingCallChannel + } + + val fullScreenPendingIntent = intentResolver.searchIncomingCallPendingIntent( + callId, + payload = emptyMap(), + ) + val shouldHaveContentIntent = true + + return ensureChannelAndBuildNotification(notificationChannel) { + priority = if (hideRingingNotificationInForeground) { + NotificationCompat.PRIORITY_LOW + } else { + NotificationCompat.PRIORITY_MAX + } + setContentTitle(title) + setContentText(description) + setSmallIcon(R.drawable.stream_video_ic_call) + setChannelId(notificationChannel.id) + setOngoing(true) + setCategory(NotificationCompat.CATEGORY_CALL) + setFullScreenIntent(fullScreenPendingIntent, true) + if (shouldHaveContentIntent) { + setContentIntent(fullScreenPendingIntent) + } else { + val emptyIntent = PendingIntent.getActivity( + application, + 0, + Intent(), + PendingIntent.FLAG_IMMUTABLE, + ) + setContentIntent(emptyIntent) + setAutoCancel(false) + } + } + } + + else -> getSettingUpCallNotification() + } + } + @OptIn(ExperimentalStreamVideoApi::class) private inline fun getOngoingCallNotificationInternal( callId: StreamCallId, diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamNotificationHandler.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamNotificationHandler.kt index 3cee5630f1..0836fac183 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamNotificationHandler.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamNotificationHandler.kt @@ -183,6 +183,10 @@ interface StreamNotificationProviderWithPayload { ): Notification? } +interface StreamSettingUpCallNotificationProvider { + fun getSettingUpCallNotification(trigger: String, callId: StreamCallId): Notification? +} + interface StreamNotificationUpdatesProvider { /** @@ -228,7 +232,7 @@ interface StreamNotificationUpdatesProvider { ): Notification? } -interface StreamNotificationProvider : StreamNotificationProviderWithPayload { +interface StreamNotificationProvider : StreamNotificationProviderWithPayload, StreamSettingUpCallNotificationProvider { /** * Customize the notification when you receive a push notification for ringing call with type [RingingState.Incoming] @@ -348,6 +352,13 @@ interface StreamNotificationProvider : StreamNotificationProviderWithPayload { * * @return A [Notification] object. */ + @Deprecated( + "Use StreamSettingUpCallNotificationProvider.getSettingUpCallNotification(trigger,callId)", + replaceWith = ReplaceWith( + "StreamSettingUpCallNotificationProvider.getSettingUpCallNotification(trigger,callId)", + ), + level = DeprecationLevel.WARNING, + ) fun getSettingUpCallNotification(): Notification? } diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/NoOpNotificationHandler.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/NoOpNotificationHandler.kt index 80b095a59a..f2b05a99da 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/NoOpNotificationHandler.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/NoOpNotificationHandler.kt @@ -115,7 +115,18 @@ internal object NoOpNotificationHandler : NotificationHandler { payload: Map, ): Notification? = null + @Deprecated( + "Use StreamSettingUpCallNotificationProvider.getSettingUpCallNotification(trigger,callId)", + replaceWith = ReplaceWith( + "StreamSettingUpCallNotificationProvider.getSettingUpCallNotification(trigger,callId)", + ), + level = DeprecationLevel.WARNING, + ) override fun getSettingUpCallNotification(): Notification? = null + override fun getSettingUpCallNotification( + trigger: String, + callId: StreamCallId, + ): Notification? = null @Deprecated( level = DeprecationLevel.ERROR, diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/service/CallService.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/service/CallService.kt index 330183b448..1f7f485e66 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/service/CallService.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/service/CallService.kt @@ -216,7 +216,12 @@ internal open class CallService : Service() { * Mandatory, if not called then it will throw exception if we directly decide to stop the service. * For example: it will stop the service if [verifyPermissions] is false */ - promoteToFgServiceIfNoActiveCall(params.streamVideo, notificationId, params.trigger) + promoteToFgServiceIfNoActiveCall( + params.streamVideo, + notificationId, + params.trigger, + params.callId, + ) val call = params.streamVideo.call(params.callId.type, params.callId.id) // Rendering incoming call does not need audio/video permissions @@ -654,8 +659,9 @@ internal open class CallService : Service() { videoClient: StreamVideoClient, notificationId: Int, trigger: String, + callId: StreamCallId, ) { - videoClient.getSettingUpCallNotification()?.let { notification -> + videoClient.getSettingUpCallNotification(trigger, callId)?.let { notification -> startForegroundWithServiceType( notificationId, notification, From 3d46d029f0ad9e5131608cbed423ca5cadc1bd13 Mon Sep 17 00:00:00 2001 From: rahullohra Date: Wed, 1 Apr 2026 17:29:25 +0530 Subject: [PATCH 2/4] fix: fix breaking changes --- .../api/stream-video-android-core.api | 3 ++- .../handlers/StreamDefaultNotificationHandler.kt | 14 +------------- .../handlers/StreamNotificationHandler.kt | 10 +++++++++- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/stream-video-android-core/api/stream-video-android-core.api b/stream-video-android-core/api/stream-video-android-core.api index 1f1e8c7aed..3c6dc19f9f 100644 --- a/stream-video-android-core/api/stream-video-android-core.api +++ b/stream-video-android-core/api/stream-video-android-core.api @@ -13554,7 +13554,8 @@ public abstract interface class io/getstream/video/android/core/notifications/ha public static synthetic fun getOngoingCallNotification$default (Lio/getstream/video/android/core/notifications/handlers/StreamNotificationProvider;Lio/getstream/video/android/model/StreamCallId;Ljava/lang/String;ZIILjava/lang/Object;)Landroid/app/Notification; public fun getRingingCallNotification (Lio/getstream/video/android/core/RingingState;Lio/getstream/video/android/model/StreamCallId;Ljava/lang/String;Z)Landroid/app/Notification; public static synthetic fun getRingingCallNotification$default (Lio/getstream/video/android/core/notifications/handlers/StreamNotificationProvider;Lio/getstream/video/android/core/RingingState;Lio/getstream/video/android/model/StreamCallId;Ljava/lang/String;ZILjava/lang/Object;)Landroid/app/Notification; - public abstract fun getSettingUpCallNotification ()Landroid/app/Notification; + public fun getSettingUpCallNotification ()Landroid/app/Notification; + public fun getSettingUpCallNotification (Ljava/lang/String;Lio/getstream/video/android/model/StreamCallId;)Landroid/app/Notification; } public abstract interface class io/getstream/video/android/core/notifications/handlers/StreamNotificationProviderWithPayload { diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt index 3eccf032f8..0b23fb22ac 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt @@ -575,7 +575,6 @@ constructor( callId, payload = emptyMap(), ) - val shouldHaveContentIntent = true return ensureChannelAndBuildNotification(notificationChannel) { priority = if (hideRingingNotificationInForeground) { @@ -590,18 +589,7 @@ constructor( setOngoing(true) setCategory(NotificationCompat.CATEGORY_CALL) setFullScreenIntent(fullScreenPendingIntent, true) - if (shouldHaveContentIntent) { - setContentIntent(fullScreenPendingIntent) - } else { - val emptyIntent = PendingIntent.getActivity( - application, - 0, - Intent(), - PendingIntent.FLAG_IMMUTABLE, - ) - setContentIntent(emptyIntent) - setAutoCancel(false) - } + setContentIntent(fullScreenPendingIntent) } } diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamNotificationHandler.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamNotificationHandler.kt index 0836fac183..efe6908da0 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamNotificationHandler.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamNotificationHandler.kt @@ -359,7 +359,15 @@ interface StreamNotificationProvider : StreamNotificationProviderWithPayload, St ), level = DeprecationLevel.WARNING, ) - fun getSettingUpCallNotification(): Notification? + fun getSettingUpCallNotification(): Notification? = null + + // Inside StreamNotificationProvider interface, add: + override fun getSettingUpCallNotification( + trigger: String, + callId: StreamCallId, + ): Notification? { + return getSettingUpCallNotification() + } } /** From 2d3803e6e355ca01cae66b405780d1c5cbc7ff85 Mon Sep 17 00:00:00 2001 From: rahullohra Date: Wed, 1 Apr 2026 17:49:24 +0530 Subject: [PATCH 3/4] fix: added null check for fullScreenPendingIntent --- .../handlers/StreamDefaultNotificationHandler.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt index 0b23fb22ac..fd82a8042d 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt @@ -576,6 +576,12 @@ constructor( payload = emptyMap(), ) + if (fullScreenPendingIntent == null) { + logger.w { + "[getSettingUpCallNotification] fullScreenPendingIntent is null; lock-screen wake-up may not work." + } + return getSettingUpCallNotification() + } return ensureChannelAndBuildNotification(notificationChannel) { priority = if (hideRingingNotificationInForeground) { NotificationCompat.PRIORITY_LOW From 7f4d864f32d3dc52e979df2c5463c410e86b2885 Mon Sep 17 00:00:00 2001 From: rahullohra Date: Wed, 1 Apr 2026 17:51:29 +0530 Subject: [PATCH 4/4] fix: revert fullScreenPendingIntent --- .../notifications/handlers/StreamDefaultNotificationHandler.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt index fd82a8042d..579dc1b521 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt @@ -580,7 +580,6 @@ constructor( logger.w { "[getSettingUpCallNotification] fullScreenPendingIntent is null; lock-screen wake-up may not work." } - return getSettingUpCallNotification() } return ensureChannelAndBuildNotification(notificationChannel) { priority = if (hideRingingNotificationInForeground) {