Skip to content

Conversation

@rahul-lohra
Copy link
Contributor

@rahul-lohra rahul-lohra commented Dec 23, 2025

Goal

  1. Fix FG Service Notification dismiss from Notification Tray
  2. Fix Ringing State update process
  3. Reuse same FG Service when transitioning from Ringing to Active Call instead of killing & respawn FG Service
  4. Split Call Service into smaller classes

Implementation

Core Changes

Core classes

  1. ClientState
  2. CallState
Class Change description
ClientState Instead of stopping restarting service we are now transitioning incoming/outgoing call to active on the same service
CallState - Prevent race-condition in event consumption & processing in Service Class by firing new local events when their original events are consumed
-Since we will use same service to transition from ringing to active so we need to store a reference of original notification Id
- Process LocalCallMissedEvent here so that it will work for calls which are not active

Service classes refactoring

Class Change description
ServiceIntentBuilder Creates and configures the various Intent objects used to communicate with the CallService.
ServiceLauncher Provides a clean and centralized API to start, stop, and interact with the CallService.
CallServiceLifecycleManager Manages the core business logic of starting, ending, and handling the lifecycle of a call.
CallServiceNotificationManager Responsible for creating, displaying, and updating all notifications shown by the service.
ServiceState The single source of truth that holds the current state of the service, such as active and ringing call IDs.
CallServiceEventObserver Listens to VideoEvent changes from the Call and updates the ServiceState accordingly.
CallServiceNotificationUpdateObserver Observes state changes and triggers updates to the foreground notification.
CallServiceRingingStateObserver Manages the ringing state and handles transitions between incoming, active, and idle calls.

Util Classes

Class Change description
Debouncer To debounce the stopping of FG Service to ensure enough time has passed for the system to process the notification removal.
Throttler Throttling the service by [CallService.SERVICE_DESTROY_THROTTLE_TIME_MS] such that the stop service is invoked once (at least less frequently)

Testing

Fix FG Service Notification dismiss from Notification Tray

  1. Open the notification drawer in callee phone
  2. Make a call and end the call within 1-2 second.
  3. The notification should properly update on the callee's phone

Service lifecycle

  1. When a call is ended, service should get destroyed (check from the logs)

Summary by CodeRabbit

  • New Features

    • Missed-call notifications now include caller/creator info and use stable notification IDs.
    • Notifications and foreground service starts are permission-aware and choose appropriate service types.
    • Debouncing/throttling reduces rapid stop/start service actions for smoother behavior.
  • Bug Fixes

    • More consistent ringing → accepted transitions across devices.
    • Improved notification lifecycle: better updates, cancellations, and timing when multiple calls occur.

✏️ Tip: You can customize this high-level summary in your review settings.

Adds more detailed logging to the `CallEventObserver` to provide better insight into the handling of incoming call events.
When a `CallRejectedEvent` is received, the `createdBy` field on the call state is now updated with the user who created the call.
Introduces `LocalCallAcceptedEvent` and `LocalCallRejectedEvent` to represent call state changes originating from the local device.

These new local events are now used in `CallEventObserver` instead of the generic `CallAcceptedEvent` and `CallRejectedEvent`, providing a clearer distinction for handling call lifecycle states like accepting a call. Additionally, `CallState` now fires these local events, improving the accuracy of event-driven logic.
@rahul-lohra rahul-lohra self-assigned this Dec 23, 2025
# Conflicts:
#	stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/Call.kt
#	stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/service/CallService.kt
Adds a reason when leaving a call from the `CallLifecycleManager`. This provides more context for why the call was ended, distinguishing between different scenarios such as the task being removed for an ongoing or incoming call.
@github-actions
Copy link
Contributor

github-actions bot commented Dec 23, 2025

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.

🎉 Great job! This PR is ready for review.

@github-actions
Copy link
Contributor

github-actions bot commented Dec 23, 2025

SDK Size Comparison 📏

SDK Before After Difference Status
stream-video-android-core 11.94 MB 11.96 MB 0.02 MB 🟢
stream-video-android-ui-xml 5.68 MB 5.68 MB 0.00 MB 🟢
stream-video-android-ui-compose 6.27 MB 6.27 MB 0.00 MB 🟢

aleksandar-apostolov and others added 13 commits December 24, 2025 10:32
Renames several components within the `CallService` infrastructure to improve clarity by prefixing them with "CallService". This includes managers and observers.

The events `LocalCallAcceptedEvent` and `LocalCallRejectedEvent` are renamed to `LocalCallAcceptedPostEvent` and `LocalCallRejectedPostEvent` respectively to better reflect their purpose.

Additionally, this change introduces a comprehensive suite of unit tests for the `CallService` and its related components, covering:
- Lifecycle and notification management
- Event, ringing state, and notification update observers
- Foreground service permission handling
- Debouncer and Throttler utilities
Renames `LocalCallAcceptedEvent` and `LocalCallRejectedEvent` to `LocalCallAcceptedPostEvent` and `LocalCallRejectedPostEvent` respectively, to better reflect that they are events sent *after* the action has occurred.
Adds `notificationId` as a parameter to the `updateNotification` function. This allows for updating the notification with a specific ID. The previous `updateNotification` function without the ID has been deprecated.
Adds an overloaded version of the `updateNotification` method that doesn't require a notification ID, simplifying its usage.
The `transitionToAcceptCall` function in `ClientState` is now marked as `internal`, restricting its usage to within the same module. This change also updates the public API definition.
Removes an unnecessary `stopService` call that was being made immediately after `startService` in `ServiceLauncher`.
Adds a TODO comment to `DefaultNotificationDispatcher.kt` to ensure a new fix is verified before merging.
Adds a TODO comment to `DefaultNotificationDispatcher.kt` to ensure a new fix is verified before merging.
Adds the `RobolectricTestRunner` to `ServiceStateTest` to address test failures that occurred when running all tests together.

The `unregisterToggleCameraBroadcastReceiver` test has been moved to the end of the file as it was failing for unknown reasons, and a `println` has been added for debugging.
When a call is initiated, it now transitions through the `RingingState.Outgoing` state. This change ensures that a foreground service with an outgoing call notification is started, providing immediate feedback to the user that a call is being placed.

A delay is introduced before starting the foreground service for outgoing calls to allow the system to properly transition the call state.
@aleksandar-apostolov
Copy link
Contributor

Its a good refactor which extracts some concerns from the CallService. I left some comments that we need to look into before merging.

@rahul-lohra rahul-lohra changed the title Improve CallService lifecycle, notification handling, and ringing-to-active transition [AND-962] Improve CallService lifecycle, notification handling, and ringing-to-active transition Jan 16, 2026
@rahul-lohra rahul-lohra changed the title [AND-962] Improve CallService lifecycle, notification handling, and ringing-to-active transition Improve CallService lifecycle, notification handling, and ringing-to-active transition Jan 16, 2026
@rahul-lohra rahul-lohra changed the base branch from develop to develop-v2 January 16, 2026 07:22
@aleksandar-apostolov
Copy link
Contributor

Shouldn't this go towards develop instead?

@rahul-lohra
Copy link
Contributor Author

Shouldn't this go towards develop instead?

Yes I will correct it

@rahul-lohra rahul-lohra changed the base branch from develop-v2 to develop January 19, 2026 11:49
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
1 Security Hotspot
55.7% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@aleksandar-apostolov aleksandar-apostolov merged commit 01f87fb into develop Jan 26, 2026
11 of 12 checks passed
@aleksandar-apostolov aleksandar-apostolov deleted the bugfix/rahullohra/refactor-call-service branch January 26, 2026 09:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:improvement Enhances an existing feature or code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants