…active transition (#1588)
* Refactor call service into smaller classes
* chore: add logging to notification and lifecycle managers
* feat: Add logging to CallEventObserver
Adds more detailed logging to the `CallEventObserver` to provide better insight into the handling of incoming call events.
* feat: Update createdBy on call rejected event
When a `CallRejectedEvent` is received, the `createdBy` field on the call state is now updated with the user who created the call.
* chore: add createdByUserId in LocalCallMissedEvent
* chore: fix missed imports
* chore: fix service cancellation from LocalCallMissedEvent
* chore: refactor
* chore: fix notification id for missed-call
* chore: add logic for time-sensitive services
* chore: temp
* feat: Introduce local call events for better state handling
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.
* feat: Add reason when leaving call from service
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.
* refactor: Rename CallService components and add tests
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
* refactor: Rename local call events
Renames `LocalCallAcceptedEvent` and `LocalCallRejectedEvent` to `LocalCallAcceptedPostEvent` and `LocalCallRejectedPostEvent` respectively, to better reflect that they are events sent *after* the action has occurred.
* feat: Add notificationId to updateNotification
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.
* feat: Add `updateNotification` without notification ID
Adds an overloaded version of the `updateNotification` method that doesn't require a notification ID, simplifying its usage.
* feat: Make `transitionToAcceptCall` internal
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.
* fix: Remove stopService call from ServiceLauncher
Removes an unnecessary `stopService` call that was being made immediately after `startService` in `ServiceLauncher`.
* chore: Add a TODO comment
Adds a TODO comment to `DefaultNotificationDispatcher.kt` to ensure a new fix is verified before merging.
* chore: Add a TODO comment
Adds a TODO comment to `DefaultNotificationDispatcher.kt` to ensure a new fix is verified before merging.
* test: Use RobolectricTestRunner in ServiceStateTest
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.
* chore: Improve documentation and make local events internal
* feat: Add support for outgoing call notifications
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.
* Refactor: Improve notification and service handling for calls
This commit introduces several improvements to the handling of call notifications and the lifecycle of the `CallService`.
The `handleNotification` method in `CallService` now returns a `CallServiceHandleNotificationResult` enum. This allows for more granular control over the service's state, enabling it to continue running without re-initialization (`START_NO_CHANGE`) or to be redelivered if an error occurs.
Additionally, the logic for handling `LocalCallMissedEvent` has been moved from `CallServiceEventObserver` directly into the `CallState`. This change ensures that incoming call notifications are correctly dismissed when another call is already active, without unnecessarily stopping the foreground service.
Other changes include:
- Preventing the start of a new `CallService` if one is already running for another call.
- Adding a short delay before starting the foreground service when a call is accepted to prevent race conditions.
- Enhancing logging for better debugging of service and notification lifecycles.
* fix: Remove leftover comments and add clarity
Removes a leftover development comment in `ServiceLauncher.kt`.
Adds a clarifying comment in `ClientState.kt` to explain the logic for transitioning incoming/outgoing calls to an active state within the same service.
* chore: Remove temporary logging
Removes temporary "Noob" log messages from `ClientState`, `CallServiceEventObserver`, and `CallService`. Also removes some commented-out code from `CallServiceEventObserver`.
* fix: Correctly report service running state
Updates the `isServiceRunning` check to return `false` when the service is not running.
* refactor: Improve service running check
Removes the static `runningServiceClassName` set from `CallService` and updates the `isServiceRunning` check. The `ServiceIntentBuilder.isServiceRunning` method now uses `ActivityManager.getRunningServices()` to determine if a service is active. This provides a more reliable check based on the Android system's state.
The method signature for `isServiceRunning` has been updated to require a `Context` parameter.
* refactor: Extract Throttler from Debouncer
Extracts the `Throttler` object from `Debouncer.kt` into its own dedicated file, `Throttler.kt`.
This change also moves the `debouncer` instance in `CallService` to be a top-level property and adds documentation explaining its purpose.
* feat: Throttle call service stop requests
Throttles the `stopService` requests in `ServiceLauncher` to prevent the service from being stopped and restarted too frequently.
The throttling is set to `1000ms` using the new `SERVICE_DESTROY_THROTTLE_TIME_MS` constant defined in `CallService`.
* chore: Re-enable graceful service stop
This commit re-enables the `stopServiceGracefully()` call, which was previously commented out. The `source` parameter has also been removed from the `stopServiceGracefully()` method signature.
* chore: Remove TODO comment
Removes a `// TODO` comment from `DefaultNotificationDispatcher`.
* chore: Use notificationId from call state
Retrieves the `notificationId` from the `call.state` when available, instead of calculating it. This ensures a consistent notification ID is used for ongoing, incoming, and outgoing call notifications within the `ServiceNotificationRetriever` and `CallServiceNotificationUpdateObserver`.
* refactor: Use Call specific notification ID in tests
Updates the `ServiceNotificationRetrieverTest` to use the call-specific notification ID generated by `callId.getNotificationId()` instead of the call ID's hashcode. This aligns the test with the actual implementation for generating notification IDs.
* fix: Cancel correct notification ID for calls
When cancelling notifications for a call, the `CallServiceNotificationManager` now correctly uses the `notificationId` from the call's state.
Previously, it was attempting to cancel a hardcoded `Incoming` notification type ID, which might not be the correct one. This change ensures the notification that was actually shown is the one that gets cancelled.
* chore: Add logging and fix notification ID usage
Adds more detailed logging to the `CallServiceNotificationUpdateObserver` for better insight into notification updates.
Also, this change ensures that an existing notification ID from the call state is used before generating a new one when showing call notifications.
* Refactor: Improve call service logic and logging
This commit refactors the `CallService` to improve clarity and maintainability.
Key changes include:
- Extracting the notification handling logic into smaller, more focused functions (`handleNullNotification`, `startForegroundForCall`).
- Passing the `serviceScope` to `CallServiceEventObserver` to ensure its lifecycle is tied to the service.
- Enhancing logging throughout the call service and related managers to provide more detailed information for debugging, including hashcodes to identify specific object instances.
- Adding `serviceScope.cancel()` in `onDestroy` to ensure all coroutines are properly cancelled when the service is destroyed.
* refactor: Improve incoming call and service stop logic
Refactors the `IncomingCallPresenter` to simplify its logic by extracting functionality into smaller, more descriptive private functions. This improves readability and makes the different paths for handling incoming calls clearer.
The `buildStopIntent` method in `ServiceIntentBuilder` is updated to only return an intent if the corresponding service is actually running, preventing unnecessary stop commands.
Additionally, this commit:
- Removes the handling of `LocalCallMissedEvent` from `CallServiceEventObserver` as it's no longer needed.
- Enhances tests for `IncomingCallPresenter` and `ServiceIntentBuilder` to cover the new logic and edge cases.
* chore: Improve foreground service stability and test coverage
This commit introduces several improvements to enhance the stability of the foreground `CallService` and increases test coverage across various components.
Key changes include:
- A `Debouncer` was added to `CallService` to gracefully handle service stop requests, preventing premature termination.
- Introduced `debouncer.cancel()` in `CallService.onDestroy()` to clean up pending actions.
- The `ClientState.setActiveCall` logic now uses a constant for the service transition delay.
- Added and fixed tests for `CallServiceLifecycleManager`, `CallServiceNotificationManager`, and `ServiceIntentBuilder` to ensure more reliable behavior.
- Minor fixes in logging and code cleanup.
* Fix: Make `CallService` safer against null `StreamVideo` instance
Makes `CallService` more robust by handling cases where `StreamVideo.instanceOrNull()` might return null.
The `notificationConfig()` function now returns a nullable `NotificationConfig?` to prevent potential crashes. This change is propagated to `maybeHandleMediaIntent` to ensure it safely handles the nullable configuration.
* Refactor: Move debugPrintLastStackFrames to AndroidUtils
* docs: Update kdoc for notifications api (#1602)
* fix: refactor code
* fix: update year
* fix: store notification id in ServiceStateSnapshot.kt
* fix: fix tests
* chore: Use client scope for rejecting calls from service
* fix: fix test
---------
Co-authored-by: Aleksandar Apostolov <[email protected]>
Goal
Update kdoc for notifications
Implementation
Kdoc changes
🎨 UI Changes
None
Testing
Not required
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.