Skip to content

Fix notification dismissal for Leave/Hang Up notification actions#1732

Merged
rahul-lohra merged 17 commits into
developfrom
bugfix/rahullohra/leave-notification-dismissal
Jun 23, 2026
Merged

Fix notification dismissal for Leave/Hang Up notification actions#1732
rahul-lohra merged 17 commits into
developfrom
bugfix/rahullohra/leave-notification-dismissal

Conversation

@rahul-lohra

@rahul-lohra rahul-lohra commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Goal

Closes #AND-1252
Stacked on #1731

A customer reported that call notifications were not being dismissed after tapping the Leave/Hang Up action from the notification.

Notification removal can be triggered from two different components:

  1. CallServiceNotificationManager
  2. LeaveCallBroadcastReceiver

During the investigation, we found that LeaveCallBroadcastReceiver was unable to retrieve the correct notification ID from INTENT_EXTRA_NOTIFICATION_ID.
The SDK was incorrectly populating this extra with the call CID instead of the notification ID when creating notification action intents.

As a result, LeaveCallBroadcastReceiver could not cancel the corresponding notification, leaving stale notifications visible after the call was ended from the notification action.

This change ensures that the correct notification ID is attached to the intent so that notifications are properly dismissed when users leave or hang up a call from the notification.

Implementation

Before After
image image

🎨 UI Changes

None

Testing

Test notification dismissal for

  1. Regular Calls - Try join and leave back and forth quickly - Leave from Notification/ Leave from hangup button
  2. 1-1 Calls
  3. Livestream calls

Summary by CodeRabbit

  • Bug Fixes

    • Enhanced notification ID management to ensure incoming call notifications and leave call actions are correctly processed and dismissed across all scenarios.
  • Chores

    • Deprecated legacy notification ID constant to streamline internal notification tracking.

@rahul-lohra rahul-lohra self-assigned this Jun 23, 2026
@rahul-lohra rahul-lohra requested a review from a team as a code owner June 23, 2026 05:55
@rahul-lohra rahul-lohra added the pr:bug Fixes a bug label Jun 23, 2026
@github-actions

github-actions Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

PR checklist ✅

All required conditions are satisfied:

  • Title length is OK (or ignored by label).
  • At least one pr: label exists.
  • Sections ### Goal, ### Implementation, and ### Testing are filled, or the PR is bot-authored.
  • An issue is linked (Linear ticket or GitHub issue), or the PR is bot-authored.

🎉 Great job! This PR is ready for review.

@rahul-lohra rahul-lohra changed the title Fix notification dismissal for Leave/Hang Up notification actions [AND-1252] Fix notification dismissal for Leave/Hang Up notification actions Jun 23, 2026
@rahul-lohra rahul-lohra changed the title [AND-1252] Fix notification dismissal for Leave/Hang Up notification actions Fix notification dismissal for Leave/Hang Up notification actions Jun 23, 2026
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Deprecates INTENT_EXTRA_NOTIFICATION_ID in NotificationHandler and updates the notification ID resolution scheme: DefaultStreamIntentResolver now writes INTENT_EXTRA_CALL_CID instead, LeaveCallBroadcastReceiver reads the ID from call.state.notificationIdFlow while also canceling the legacy hashCode-based ID, and AbstractNotificationActivity derives the incoming notification ID from the call CID. Four TODO comments mark remaining hashCode() usages in StreamDefaultNotificationHandler.

Changes

Notification ID migration away from intent extras

Layer / File(s) Summary
Deprecate INTENT_EXTRA_NOTIFICATION_ID and fix intent resolver
...notifications/NotificationHandler.kt, ...notifications/DefaultStreamIntentResolver.kt
INTENT_EXTRA_NOTIFICATION_ID is annotated @Deprecated pointing to CallState.notificationIdFlow and StreamCallId.getNotificationId. buildComponentIntent switches from writing INTENT_EXTRA_NOTIFICATION_ID = callId.cid to INTENT_EXTRA_CALL_CID = callId.
Update notification dismissal in receiver and activity
...receivers/LeaveCallBroadcastReceiver.kt, ...notification/AbstractNotificationActivity.kt
LeaveCallBroadcastReceiver.onReceive derives the notification ID from call.state.notificationIdFlow.value, computes a legacy ID via StreamCallId.fromCallCid(call.cid).hashCode(), and cancels both. AbstractNotificationActivity.dismissIncomingCallNotifications is refactored to accept a StreamCallId and derive the ID via callCid.getNotificationId(NotificationType.Incoming).
TODO markers for remaining hashCode usages
...notifications/handlers/StreamDefaultNotificationHandler.kt
Four TODO comments inserted at live-call, generic, simple ongoing, and minimal media-style notification paths marking StreamCallId.hashCode() for replacement with getNotificationId.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 A rabbit hopped by with a CID in paw,
"No more stale intent extras — that was the flaw!"
Two IDs cancelled, the legacy laid low,
notificationIdFlow leads where notifications go.
TODOs are planted like seeds in the ground,
A cleaner ID scheme has finally been found! 🔔

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: fixing notification dismissal for Leave/Hang Up notification actions, which directly addresses the core issue of stale notifications not being removed.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed PR description comprehensively covers the goal, root cause, implementation, testing strategy, and includes relevant before/after diagrams explaining the fix.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bugfix/rahullohra/leave-notification-dismissal

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt (1)

206-206: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Enhance TODO comments with specific NotificationType guidance to prevent ID mismatches during migration.

The four TODO markers appropriately flag locations where callId.hashCode() should be replaced with StreamCallId.getNotificationId(NotificationType). However, the placeholder "appropriateType" is vague and may lead to incorrect NotificationType choices during implementation, which would re-introduce ID mismatches between handler posting and downstream dismissal.

Per the migration documented in Context Snippet 4 (AbstractNotificationActivity dismisses with getNotificationId(NotificationType.Incoming)), the NotificationType selection is critical. Different notification scenarios (live, incoming, ongoing, outgoing, livestream) may use different types, and misalignment will cause NotificationManager.cancel(wrongId) failures.

Consider refining each TODO to specify the likely NotificationType:

  • Line 206 (onLiveCall): Determine whether LiveCall or another type applies.
  • Line 257 (onNotification): Clarify which type this generic path should use.
  • Line 750 (getSimpleOngoingCallNotification): Likely Ongoing, but confirm whether separate types exist for outgoing vs. ongoing.
  • Line 1186 (getMinimalMediaStyleNotification): Likely Ongoing or LiveCall, needs verification.

Additionally, verify that all notification posting paths in this handler are marked. If additional unmarked paths exist (e.g., for missed calls, generic notifications), they should also be updated in the follow-up layer to maintain consistency.

📋 Suggested refined TODOs (example)
- // TODO: Replace StreamCallId.hashCode with StreamCallId.getNotificationId(appropriateType)
+ // TODO: Replace callId.hashCode() with callId.getNotificationId(NotificationType.LiveCall) — confirm type matches downstream dismissal in AbstractNotificationActivity/LeaveCallBroadcastReceiver

- // TODO: Replace StreamCallId.hashCode with StreamCallId.getNotificationId(appropriateType)
+ // TODO: Replace callId.hashCode() with callId.getNotificationId(NotificationType.???) — determine correct type for generic notification path

- // TODO: Replace StreamCallId.hashCode with StreamCallId.getNotificationId(appropriateType)
+ // TODO: Replace callId.hashCode() with callId.getNotificationId(NotificationType.Ongoing) — verify consistency with downstream isOutgoingCall branching

- // TODO: Replace StreamCallId.hashCode with StreamCallId.getNotificationId(appropriateType)
+ // TODO: Replace callId.hashCode() with callId.getNotificationId(NotificationType.Ongoing) or NotificationType.LiveCall — confirm media-style livestream type

Also applies to: 257-257, 750-750, 1186-1186

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt`
at line 206, The TODO comments at lines 206, 257, 750, and 1186 are too vague
with "appropriateType" placeholders, which will lead to incorrect
NotificationType choices during the migration from callId.hashCode() to
StreamCallId.getNotificationId(NotificationType). For the onLiveCall method, the
TODO should specify likely LiveCall type; for the onNotification method, clarify
which type this generic path requires; for getSimpleOngoingCallNotification,
confirm whether Ongoing or a separate outgoing type applies; and for
getMinimalMediaStyleNotification, specify whether Ongoing or LiveCall is
appropriate. Update each TODO comment to include the specific NotificationType
that should be used when the method is refactored, ensuring that the
notification IDs posted in these handlers match the IDs used when dismissing
notifications downstream (such as in AbstractNotificationActivity).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/receivers/LeaveCallBroadcastReceiver.kt`:
- Around line 49-59: The notification cancellation in
LeaveCallBroadcastReceiver's onReceive method is performed after call.leave(),
which means if call.leave() throws an exception, the notification cleanup code
will not execute. Wrap the call.leave() invocation in a try-finally block,
moving the notificationManager.cancel() calls (for both notificationId and
legacyNotificationId) into the finally block to guarantee notification cleanup
occurs regardless of whether call.leave() succeeds or fails.

---

Nitpick comments:
In
`@stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt`:
- Line 206: The TODO comments at lines 206, 257, 750, and 1186 are too vague
with "appropriateType" placeholders, which will lead to incorrect
NotificationType choices during the migration from callId.hashCode() to
StreamCallId.getNotificationId(NotificationType). For the onLiveCall method, the
TODO should specify likely LiveCall type; for the onNotification method, clarify
which type this generic path requires; for getSimpleOngoingCallNotification,
confirm whether Ongoing or a separate outgoing type applies; and for
getMinimalMediaStyleNotification, specify whether Ongoing or LiveCall is
appropriate. Update each TODO comment to include the specific NotificationType
that should be used when the method is refactored, ensuring that the
notification IDs posted in these handlers match the IDs used when dismissing
notifications downstream (such as in AbstractNotificationActivity).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 726d1491-db51-454c-905d-4b1030d74d0c

📥 Commits

Reviewing files that changed from the base of the PR and between 8c237bf and 838d4b9.

📒 Files selected for processing (5)
  • stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/DefaultStreamIntentResolver.kt
  • stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/NotificationHandler.kt
  • stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt
  • stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/receivers/LeaveCallBroadcastReceiver.kt
  • stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/notification/AbstractNotificationActivity.kt
💤 Files with no reviewable changes (1)
  • stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/DefaultStreamIntentResolver.kt

@github-actions

Copy link
Copy Markdown
Contributor

SDK Size Comparison 📏

SDK Before After Difference Status
stream-video-android-core 12.27 MB 12.27 MB 0.00 MB 🟢
stream-video-android-ui-xml 5.68 MB 5.68 MB 0.00 MB 🟢
stream-video-android-ui-compose 6.20 MB 6.20 MB 0.00 MB 🟢

@aleksandar-apostolov aleksandar-apostolov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — bug analysis is right and the fix is targeted.

@rahul-lohra rahul-lohra force-pushed the bugfix/rahullohra/battery-restrictions branch from 8c237bf to a0f1e7c Compare June 23, 2026 08:57
Base automatically changed from bugfix/rahullohra/battery-restrictions to develop June 23, 2026 09:05
@rahul-lohra rahul-lohra force-pushed the bugfix/rahullohra/leave-notification-dismissal branch 2 times, most recently from 6436d35 to 838d4b9 Compare June 23, 2026 09:12
…cation-dismissal

# Conflicts:
#	stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

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

See analysis details on SonarQube Cloud

@rahul-lohra rahul-lohra merged commit a60b820 into develop Jun 23, 2026
20 of 22 checks passed
@rahul-lohra rahul-lohra deleted the bugfix/rahullohra/leave-notification-dismissal branch June 23, 2026 09:47
@stream-public-bot stream-public-bot added the released Included in a release label Jun 23, 2026
@stream-public-bot

Copy link
Copy Markdown
Collaborator

🚀 Available in v1.28.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:bug Fixes a bug released Included in a release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants