-
Notifications
You must be signed in to change notification settings - Fork 40
feat: implement our own keep call alive foreground service instead of notifee #2082
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: implement our own keep call alive foreground service instead of notifee #2082
Conversation
### 💡 Overview In case when caller is in active call, they can be interrupted by incoming call even when `rejectCallWhenBusy` is set to `true`. ### 📝 Implementation notes 🎫 Ticket: https://linear.app/stream/issue/RN-326/rejectcallwhenbusy-is-not-working-for-caller
### 💡 Overview ### 📝 Implementation notes 🎫 Ticket: https://linear.app/stream/issue/XYZ-123 📑 Docs: https://github.com/GetStream/docs-content/pull/<id>
Introduces new `useModeration` hook that handles the `call.moderation_blur` event. Follow-up of: #1822 🎫 Ticket: https://linear.app/stream/issue/RN-329/moderation-video-blurring 📑 Docs: GetStream/docs-content#373
### 💡 Overview Implement collapsible accordion for QR code section in participants panel.
### 💡 Overview Adds PipLayout.Grid, a grid layout for PiP mode with built-in pagination and automatic column adjustment based on the current participant count. ### 📝 Implementation notes 🎫 Ticket: https://linear.app/stream/issue/REACT-702/improve-pip-while-presenting-add-grid-view-during-screenshare
…o re-mount (#2077) ### 💡 Overview This change removes the use of a randomly generated portal ID and instead uses a ref backed DOM element as the FloatingPortal root. Using Math.random() during render is not recommended and causes issues with some versions of React Compiler since the compiler may strip or reorder memoization.
Adds dev page + API for the new `GetCallStatsMap` endpoint. Ref: GetStream/chat#10910
…ra (#2080) This code used to be buggy, and when combined with`usePersistedDevicePreferences`, it was causing a race condition that caused devices to be enabled/disabled randomly, depending on who reached the critical block first. Besides that, `CameraManager` was incorrectly checking for `SEND_AUDIO` instead of `SEND_VIDEO` capability. This is fixed now, too. ### 📝 Implementation notes - The `apply` method is now refactored and made easier to understand. - `usePersistedDevicePreferences` now sets the `deferServerDefaults` flag that prevents applying server-side defaults, as the user preferences should always take precedence. This hook handles the initial device setup, too, so we aren't losing the default settings. 🎫 Ticket: https://linear.app/stream/issue/REACT-737/improve-applying-of-default-device-preferences 📑 Docs: GetStream/docs-content#896
This update introduces a new service, StreamCallKeepAliveHeadlessService, to the AndroidManifest.xml, enabling foreground service capabilities for media playback, camera, and microphone. This enhancement aims to improve the app's performance and reliability during call handling.
…video This update addresses a race condition in the setup of server-side preferences for microphone and camera, ensuring consistent device state. The `apply` method has been refactored for clarity, and the `usePersistedDevicePreferences` hook now correctly prioritizes user preferences over server defaults. This enhancement improves the reliability of device management during calls.
…dio and video" This reverts commit dbc3c0e.
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the 📝 WalkthroughWalkthroughAdds a new SDK-owned Android foreground service for maintaining call state while the app runs in the background. Includes native service implementation, React Native bridge methods, notification management, and TypeScript headless task registration replacing prior Notifee-based approach. Changes
Sequence DiagramsequenceDiagram
participant RN as React Native App
participant Hook as useAndroidKeepCallAliveEffect
participant Bridge as StreamVideoReactNativeModule
participant Service as StreamCallKeepAliveHeadlessService
participant Notif as KeepAliveNotification
participant Headless as HeadlessJsTaskRunner
RN->>Hook: useAndroidKeepCallAliveEffect triggered
Hook->>Hook: Check Android 13+ notification permission
Hook->>Bridge: startKeepCallAliveService(callCid, channel, title, body, icon)
Bridge->>Service: buildStartIntent() + startForeground()
Service->>Notif: ensureChannel(context, channelId, channelName)
Notif-->>Service: channel created/verified
Service->>Notif: buildOngoingNotification(context, channelId, title, body, icon)
Notif-->>Service: notification object
Service->>Service: startForeground(NOTIFICATION_ID, notification)
Service-->>Bridge: service started
Bridge-->>Hook: promise resolved
rect rgb(200, 220, 255)
note over Headless: Headless Task Execution
Service->>Headless: getTaskConfig(callCid)
Headless->>Headless: retrieve keepCallAliveCallRef
Headless->>Headless: validate callCid matches
Headless->>Headless: execute taskToRun(call)
end
RN->>Hook: cleanup on unload
Hook->>Bridge: stopKeepCallAliveService()
Bridge->>Service: buildStopIntent() + stopService()
Service-->>Bridge: service stopped
Bridge-->>Hook: promise resolved
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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. Comment |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🤖 Fix all issues with AI agents
In `@packages/react-native-sdk/android/src/main/AndroidManifestNew.xml`:
- Around line 3-5: Remove the unnecessary protected permission by deleting the
<uses-permission android:name="android.permission.DEVICE_POWER" /> entry from
AndroidManifestNew.xml; keep the existing INTERNET and WAKE_LOCK permissions,
and ensure no code paths call PowerManager methods that require DEVICE_POWER
(e.g., goToSleep(), reboot())—thermal status monitoring and proximity wake locks
via PowerManager are fine without that permission.
In
`@packages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/keepalive/StreamCallKeepAliveHeadlessService.kt`:
- Around line 58-61: Replace the deprecated stopForeground(true) call in
StreamCallKeepAliveHeadlessService.onDestroy with the modern constant: call
stopForeground(Service.STOP_FOREGROUND_REMOVE) (or fully qualify
android.app.Service.STOP_FOREGROUND_REMOVE) so the service removes the
notification without using the deprecated boolean API; update imports if needed.
In
`@packages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/util/CallAliveServiceChecker.kt`:
- Around line 18-30: CallAliveServiceChecker currently compares
serviceInfo.foregroundServiceType for exact equality with
expectedForegroundServiceTypes
(ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK | CAMERA | MICROPHONE),
which fails when StreamCallKeepAliveHeadlessService omits CAMERA or MICROPHONE
bits at runtime; change the check in CallAliveServiceChecker (the code around
packageManager.getServiceInfo and expectedForegroundServiceTypes) to use bitwise
checks instead of equality—e.g., verify required bits (at minimum
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK) are present via & checks or
ensure serviceInfo.foregroundServiceType has the expected bits set with
(serviceInfo.foregroundServiceType and expectedForegroundServiceTypes) ==
serviceInfo.foregroundServiceType / or at least check the MEDIA_PLAYBACK bit—so
the validation succeeds when optional CAMERA/MICROPHONE bits are absent.
In `@packages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.ts`:
- Around line 49-58: The call to
NativeModules.StreamVideoReactNative.startKeepCallAliveService inside
useAndroidKeepCallAliveEffect is a promise but currently has no rejection
handling; update the requestAnimationFrame callback to handle rejections from
startKeepCallAliveService (either by awaiting it in an async function with
try/catch or by chaining .catch) and log/report the error (e.g., using
console.error or the existing logger) so unhandled promise rejections are
prevented; reference startKeepCallAliveService, requestAnimationFrame, and
useAndroidKeepCallAliveEffect when making the change.
- Around line 144-147: The call to
NativeModules.StreamVideoReactNative.stopKeepCallAliveService() is missing
promise error handling; update the block where keepCallAliveCallRef.current is
cleared (and foregroundServiceStartedRef.current is set to false) to call
stopKeepCallAliveService().catch(...) and log or handle the error (mirroring the
pattern used for startKeepCallAliveService()), so failures won't be swallowed —
reference keepCallAliveCallRef,
NativeModules.StreamVideoReactNative.stopKeepCallAliveService, and
foregroundServiceStartedRef when applying the change.
In `@packages/react-native-sdk/src/utils/keepCallAliveHeadlessTask.ts`:
- Around line 50-56: The code accesses StreamVideoRN.getConfig() and
config.foregroundService.android.taskToRun outside the try-catch which can throw
if the SDK isn't configured; guard this by validating getConfig() and the nested
properties (e.g., config.foregroundService.android and taskToRun) before calling
taskToRun(call), and if any are missing log a clear error via logger.error and
return early; alternatively move the getConfig() and property access into the
try block so exceptions are caught, then call taskToRun(call) inside the same
try/catch and log the caught error using the existing logger.error call.
🧹 Nitpick comments (4)
packages/react-native-sdk/src/utils/keepCallAliveHeadlessTask.ts (1)
19-63: MovehasRegistereddeclaration before the function for clarity.The current ordering is technically correct but confusing:
hasRegisteredis declared on line 61, after the function definition but before it's called. Moving the declaration before the function makes the intent clearer and follows the conventional pattern of declaring variables before use.♻️ Suggested reordering
+let hasRegistered = false; + function registerKeepCallAliveHeadlessTaskOnce() { if (Platform.OS !== 'android') return; // Registering multiple times can throw in RN; guard with a module-level flag. if (hasRegistered) return; AppRegistry.registerHeadlessTask( KEEP_CALL_ALIVE_HEADLESS_TASK_NAME, () => async (data: { callCid?: string } | undefined) => { // ... task implementation }, ); + hasRegistered = true; } -let hasRegistered = false; registerKeepCallAliveHeadlessTaskOnce(); -hasRegistered = true;packages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/keepalive/KeepAliveNotification.kt (2)
48-53: Empty fallback Intent may not provide useful behavior.When the launch activity is unavailable, creating a
PendingIntentwith an emptyIntent()will do nothing when tapped. Consider either:
- Not setting a
contentIntentat all (notification still works, just not tappable)- Logging a warning so developers are aware of the misconfiguration
💡 Suggested improvement
val contentIntent = if (launchIntent != null) { PendingIntent.getActivity(context, 0, launchIntent, pendingIntentFlags) } else { - // Fallback: empty intent to avoid crash if launch activity is missing for some reason - PendingIntent.getActivity(context, 0, Intent(), pendingIntentFlags) + // Fallback: no-op intent if launch activity is missing + android.util.Log.w("KeepAliveNotification", "Launch activity not found; notification tap will have no effect") + PendingIntent.getActivity(context, 0, Intent(), pendingIntentFlags) }
67-81: Icon fallback may fail if app icon resource ID is invalid.
appInfo.iconcan return0if no icon is set, which would cause the notification to fail. Consider adding a check:♻️ Proposed fix
// Default to the app icon return try { val appInfo = context.packageManager.getApplicationInfo(packageName, 0) - appInfo.icon + if (appInfo.icon != 0) appInfo.icon else android.R.drawable.ic_dialog_info } catch (_: PackageManager.NameNotFoundException) { android.R.drawable.ic_dialog_info }packages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.ts (1)
70-71: Setting ref during render may cause issues.
keepCallAliveCallRef.current = callis set during render, which can cause the ref to be updated even when the component doesn't commit. Consider moving this assignment into auseEffectto ensure it only updates when the component actually mounts/updates.♻️ Proposed fix
const call = useCall(); - keepCallAliveCallRef.current = call; const activeCallCid = call?.cid; + + useEffect(() => { + keepCallAliveCallRef.current = call; + return () => { + // Only clear if this hook's call is still the current one + if (keepCallAliveCallRef.current === call) { + keepCallAliveCallRef.current = undefined; + } + }; + }, [call]);
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (12)
packages/react-native-sdk/android/src/main/AndroidManifest.xmlpackages/react-native-sdk/android/src/main/AndroidManifestNew.xmlpackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.ktpackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/keepalive/KeepAliveNotification.ktpackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/keepalive/StreamCallKeepAliveHeadlessService.ktpackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/util/CallAliveServiceChecker.ktpackages/react-native-sdk/expo-config-plugin/src/withAndroidManifest.tspackages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.tspackages/react-native-sdk/src/index.tspackages/react-native-sdk/src/utils/StreamVideoRN/index.tspackages/react-native-sdk/src/utils/StreamVideoRN/types.tspackages/react-native-sdk/src/utils/keepCallAliveHeadlessTask.ts
💤 Files with no reviewable changes (1)
- packages/react-native-sdk/src/utils/StreamVideoRN/index.ts
🧰 Additional context used
📓 Path-based instructions (10)
packages/react-native-sdk/src/index.ts
📄 CodeRabbit inference engine (packages/react-native-sdk/CLAUDE.md)
packages/react-native-sdk/src/index.ts: Always callregisterGlobals()from@stream-io/react-native-webrtcbefore using WebRTC on non-web platforms in the React Native SDK entry point
Export all public SDK APIs (components, hooks, providers, types) from the mainsrc/index.tsfile, with re-exports from client and bindings packages and SDK-specific implementations
Files:
packages/react-native-sdk/src/index.ts
packages/react-native-sdk/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (packages/react-native-sdk/CLAUDE.md)
packages/react-native-sdk/src/**/*.{ts,tsx}: Use React hooks from@stream-io/video-react-bindings(viauseCall()anduseCallStateHooks()) instead of directly accessing RxJS observables from@stream-io/video-client
Use Platform.OS checks and conditional imports to gate platform-specific code (iOS, Android, web) and prevent importing platform-specific libraries on unsupported platforms
Files:
packages/react-native-sdk/src/index.tspackages/react-native-sdk/src/utils/StreamVideoRN/types.tspackages/react-native-sdk/src/utils/keepCallAliveHeadlessTask.tspackages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.ts
packages/{client,react-sdk,react-native-sdk}/src/**/*.ts?(x)
📄 CodeRabbit inference engine (AGENTS.md)
packages/{client,react-sdk,react-native-sdk}/src/**/*.ts?(x): Use TypeScript for all source code in packages/client, packages/react-sdk, and packages/react-native-sdk
Mark deprecated APIs with@deprecatedJSDoc, including rationale and replacement guidance
Throw descriptive errors or return typed error results consistently with existing patterns in public APIs
Gate internal debug logging behind an environment flag; no console noise in production builds
Never leak credentials or user data in error messages or logs
Check instance IDs and timestamps before state updates to avoid race conditions in async operations
Make public API surfaces explicit with TypeScript types and interfaces
Files:
packages/react-native-sdk/src/index.tspackages/react-native-sdk/src/utils/StreamVideoRN/types.tspackages/react-native-sdk/src/utils/keepCallAliveHeadlessTask.tspackages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx}: Use camelCase for function and property names
Narrowly scope eslint-disable comments with inline explanatory comments and rationale
Files:
packages/react-native-sdk/src/index.tspackages/react-native-sdk/expo-config-plugin/src/withAndroidManifest.tspackages/react-native-sdk/src/utils/StreamVideoRN/types.tspackages/react-native-sdk/src/utils/keepCallAliveHeadlessTask.tspackages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use PascalCase for component and type names
Files:
packages/react-native-sdk/src/index.tspackages/react-native-sdk/expo-config-plugin/src/withAndroidManifest.tspackages/react-native-sdk/src/utils/StreamVideoRN/types.tspackages/react-native-sdk/src/utils/keepCallAliveHeadlessTask.tspackages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.ts
**/*.{sh,js,ts}
📄 CodeRabbit inference engine (AGENTS.md)
Make scripts error on missing critical environment variables
Files:
packages/react-native-sdk/src/index.tspackages/react-native-sdk/expo-config-plugin/src/withAndroidManifest.tspackages/react-native-sdk/src/utils/StreamVideoRN/types.tspackages/react-native-sdk/src/utils/keepCallAliveHeadlessTask.tspackages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.ts
packages/react-native-sdk/expo-config-plugin/src/**/*.ts
📄 CodeRabbit inference engine (packages/react-native-sdk/CLAUDE.md)
Configure Expo config plugins in
expo-config-plugin/with platform-specific modifiers for Android manifest, iOS Info.plist, and app delegate modifications
Files:
packages/react-native-sdk/expo-config-plugin/src/withAndroidManifest.ts
packages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/**/*.kt
📄 CodeRabbit inference engine (packages/react-native-sdk/CLAUDE.md)
When adding Android native functionality, create Kotlin file in
android/src/main/java/com/streamvideo/reactnative/, use@ReactMethodannotation, register inStreamVideoReactNativePackage.kt, and call from TypeScript viaNativeModules.StreamVideoReactNative
Files:
packages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/util/CallAliveServiceChecker.ktpackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.ktpackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/keepalive/StreamCallKeepAliveHeadlessService.ktpackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/keepalive/KeepAliveNotification.kt
packages/react-native-sdk/src/utils/**/*.ts
📄 CodeRabbit inference engine (packages/react-native-sdk/CLAUDE.md)
Implement React Native native modules using
NativeModulesAPI and always wrap calls in try-catch blocks to handle promise rejection from native code
Files:
packages/react-native-sdk/src/utils/StreamVideoRN/types.tspackages/react-native-sdk/src/utils/keepCallAliveHeadlessTask.ts
packages/react-native-sdk/src/hooks/**/*.ts
📄 CodeRabbit inference engine (packages/react-native-sdk/CLAUDE.md)
packages/react-native-sdk/src/hooks/**/*.ts: Handle iOS backgrounding by disabling video tracks to prevent battery drain whenAppStatechanges to 'background', while keeping audio enabled
Implement Android foreground service viauseAndroidKeepCallAliveEffect()hook to prevent call termination when app is backgrounded, with automatic permission handling for POST_NOTIFICATIONS (Android 13+)
When adding new React Native hooks, useuseCall()anduseCallStateHooks()from bindings layer, handle platform-specific logic withPlatform.OS, add tests in__tests__/hooks/, and export fromsrc/hooks/index.ts
Files:
packages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.ts
🧠 Learnings (28)
📓 Common learnings
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/hooks/**/*.ts : Implement Android foreground service via `useAndroidKeepCallAliveEffect()` hook to prevent call termination when app is backgrounded, with automatic permission handling for POST_NOTIFICATIONS (Android 13+)
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/providers/StreamCall/**/*.tsx : Disable local video in background on iOS to save battery, but maintain audio connection for ongoing calls using AVAudioSession background modes
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/utils/enterPiPAndroid.ts : Create and register notification channels with proper IDs and names before starting Android foreground service, respecting platform-specific requirements (different behavior for Android 10+)
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/providers/StreamVideo.tsx : Use `StreamVideoRN.configure()` static method to set up SDK configuration including foreground service, push notification providers, and notification callbacks before mounting StreamVideo provider
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/hooks/**/*.ts : Handle iOS backgrounding by disabling video tracks to prevent battery drain when `AppState` changes to 'background', while keeping audio enabled
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/utils/push/setupIosVoipPushEvents.ts : Implement VoIP push display logic to call `CallKeep.displayIncomingCall()` within 30 seconds of receiving VoIP push notification on iOS, or the system will terminate the app
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/hooks/push/**/*.ts : Use RxJS subjects from `src/utils/push/internal/rxSubjects.ts` (like `pushTappedIncomingCallCId$`, `pushAcceptedIncomingCallCId$`, `pushRejectedIncomingCallCId$`, `voipPushNotificationCallCId$`) to bridge native push events to React hooks
📚 Learning: 2026-01-09T11:07:38.535Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/index.ts : Export all public SDK APIs (components, hooks, providers, types) from the main `src/index.ts` file, with re-exports from client and bindings packages and SDK-specific implementations
Applied to files:
packages/react-native-sdk/src/index.ts
📚 Learning: 2026-01-09T11:07:38.535Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/hooks/**/*.ts : Implement Android foreground service via `useAndroidKeepCallAliveEffect()` hook to prevent call termination when app is backgrounded, with automatic permission handling for POST_NOTIFICATIONS (Android 13+)
Applied to files:
packages/react-native-sdk/src/index.tspackages/react-native-sdk/expo-config-plugin/src/withAndroidManifest.tspackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/util/CallAliveServiceChecker.ktpackages/react-native-sdk/android/src/main/AndroidManifest.xmlpackages/react-native-sdk/src/utils/StreamVideoRN/types.tspackages/react-native-sdk/src/utils/keepCallAliveHeadlessTask.tspackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.ktpackages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.tspackages/react-native-sdk/android/src/main/AndroidManifestNew.xmlpackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/keepalive/StreamCallKeepAliveHeadlessService.ktpackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/keepalive/KeepAliveNotification.kt
📚 Learning: 2026-01-09T11:07:38.535Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/**/*.{ts,tsx} : Use Platform.OS checks and conditional imports to gate platform-specific code (iOS, Android, web) and prevent importing platform-specific libraries on unsupported platforms
Applied to files:
packages/react-native-sdk/src/index.ts
📚 Learning: 2026-01-09T11:07:38.535Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/version.ts : Store generated version information in `src/version.ts` (auto-generated via `yarn copy-version` script) and export for SDK consumers
Applied to files:
packages/react-native-sdk/src/index.tspackages/react-native-sdk/src/utils/keepCallAliveHeadlessTask.ts
📚 Learning: 2026-01-09T11:07:38.535Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/modules/**/*.ts : Structure native module TypeScript interfaces in `src/modules/` to match the exact signatures of their native implementations (Android Kotlin and iOS Swift), including parameter types and return types
Applied to files:
packages/react-native-sdk/src/index.tspackages/react-native-sdk/src/utils/keepCallAliveHeadlessTask.ts
📚 Learning: 2026-01-09T11:08:06.856Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:08:06.856Z
Learning: Applies to packages/react-sdk/**/*.{ts,tsx} : Destructure useCallStateHooks() at component top level, not in dependency arrays, to avoid unnecessary re-renders
Applied to files:
packages/react-native-sdk/src/index.ts
📚 Learning: 2026-01-09T11:07:38.535Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/utils/**/*.ts : Implement React Native native modules using `NativeModules` API and always wrap calls in try-catch blocks to handle promise rejection from native code
Applied to files:
packages/react-native-sdk/src/index.ts
📚 Learning: 2026-01-09T11:08:35.312Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T11:08:35.312Z
Learning: Applies to packages/client/src/**/*.ts?(x) : Avoid unguarded web-only APIs in shared code between React and React Native
Applied to files:
packages/react-native-sdk/src/index.ts
📚 Learning: 2026-01-09T11:07:38.535Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/components/**/*.tsx : Import translation strings from `src/translations/` and use i18n system to provide localized content for UI components
Applied to files:
packages/react-native-sdk/src/index.ts
📚 Learning: 2026-01-09T11:07:38.535Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/hooks/**/*.ts : When adding new React Native hooks, use `useCall()` and `useCallStateHooks()` from bindings layer, handle platform-specific logic with `Platform.OS`, add tests in `__tests__/hooks/`, and export from `src/hooks/index.ts`
Applied to files:
packages/react-native-sdk/src/index.tspackages/react-native-sdk/src/utils/keepCallAliveHeadlessTask.tspackages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.ts
📚 Learning: 2026-01-09T11:07:38.535Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/index.ts : Always call `registerGlobals()` from `stream-io/react-native-webrtc` before using WebRTC on non-web platforms in the React Native SDK entry point
Applied to files:
packages/react-native-sdk/src/index.tspackages/react-native-sdk/src/utils/keepCallAliveHeadlessTask.tspackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.ktpackages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.ts
📚 Learning: 2026-01-09T11:07:38.535Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/providers/StreamCall/**/*.tsx : Disable local video in background on iOS to save battery, but maintain audio connection for ongoing calls using AVAudioSession background modes
Applied to files:
packages/react-native-sdk/src/index.tspackages/react-native-sdk/expo-config-plugin/src/withAndroidManifest.tspackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/util/CallAliveServiceChecker.ktpackages/react-native-sdk/android/src/main/AndroidManifest.xmlpackages/react-native-sdk/src/utils/StreamVideoRN/types.tspackages/react-native-sdk/src/utils/keepCallAliveHeadlessTask.tspackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.ktpackages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.tspackages/react-native-sdk/android/src/main/AndroidManifestNew.xmlpackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/keepalive/StreamCallKeepAliveHeadlessService.kt
📚 Learning: 2026-01-09T11:07:38.535Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/hooks/**/*.ts : Handle iOS backgrounding by disabling video tracks to prevent battery drain when `AppState` changes to 'background', while keeping audio enabled
Applied to files:
packages/react-native-sdk/src/index.tspackages/react-native-sdk/expo-config-plugin/src/withAndroidManifest.tspackages/react-native-sdk/src/utils/StreamVideoRN/types.tspackages/react-native-sdk/src/utils/keepCallAliveHeadlessTask.tspackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.ktpackages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.ts
📚 Learning: 2026-01-09T11:07:38.535Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/utils/push/setupIosVoipPushEvents.ts : Implement VoIP push display logic to call `CallKeep.displayIncomingCall()` within 30 seconds of receiving VoIP push notification on iOS, or the system will terminate the app
Applied to files:
packages/react-native-sdk/src/index.tspackages/react-native-sdk/expo-config-plugin/src/withAndroidManifest.tspackages/react-native-sdk/src/utils/StreamVideoRN/types.tspackages/react-native-sdk/src/utils/keepCallAliveHeadlessTask.tspackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.ktpackages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.tspackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/keepalive/KeepAliveNotification.kt
📚 Learning: 2026-01-09T11:07:38.535Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/**/*.{ts,tsx} : Use React hooks from `stream-io/video-react-bindings` (via `useCall()` and `useCallStateHooks()`) instead of directly accessing RxJS observables from `stream-io/video-client`
Applied to files:
packages/react-native-sdk/src/index.tspackages/react-native-sdk/src/utils/StreamVideoRN/types.tspackages/react-native-sdk/src/utils/keepCallAliveHeadlessTask.tspackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.ktpackages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.ts
📚 Learning: 2026-01-09T11:07:38.535Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/ios/**/*.swift : When adding iOS native functionality, create Swift file in `ios/`, create Objective-C bridge with `RCT_EXTERN_METHOD`, expose via `StreamVideoReactNative.swift`, and call from TypeScript via `NativeModules.StreamVideoReactNative`
Applied to files:
packages/react-native-sdk/src/index.tspackages/react-native-sdk/src/utils/StreamVideoRN/types.tspackages/react-native-sdk/src/utils/keepCallAliveHeadlessTask.tspackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.kt
📚 Learning: 2026-01-09T11:07:38.535Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/providers/StreamVideo.tsx : Use `StreamVideoRN.configure()` static method to set up SDK configuration including foreground service, push notification providers, and notification callbacks before mounting StreamVideo provider
Applied to files:
packages/react-native-sdk/src/index.tspackages/react-native-sdk/expo-config-plugin/src/withAndroidManifest.tspackages/react-native-sdk/src/utils/StreamVideoRN/types.tspackages/react-native-sdk/src/utils/keepCallAliveHeadlessTask.tspackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.ktpackages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.ts
📚 Learning: 2026-01-09T11:07:38.535Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/expo-config-plugin/src/**/*.ts : Configure Expo config plugins in `expo-config-plugin/` with platform-specific modifiers for Android manifest, iOS Info.plist, and app delegate modifications
Applied to files:
packages/react-native-sdk/expo-config-plugin/src/withAndroidManifest.tspackages/react-native-sdk/android/src/main/AndroidManifest.xmlpackages/react-native-sdk/android/src/main/AndroidManifestNew.xml
📚 Learning: 2026-01-09T11:07:38.535Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/utils/enterPiPAndroid.ts : Create and register notification channels with proper IDs and names before starting Android foreground service, respecting platform-specific requirements (different behavior for Android 10+)
Applied to files:
packages/react-native-sdk/expo-config-plugin/src/withAndroidManifest.tspackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/util/CallAliveServiceChecker.ktpackages/react-native-sdk/src/utils/StreamVideoRN/types.tspackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.ktpackages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.tspackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/keepalive/StreamCallKeepAliveHeadlessService.ktpackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/keepalive/KeepAliveNotification.kt
📚 Learning: 2026-01-09T11:07:38.535Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/utils/push/**/*.ts : Safely detect optional library availability using helper functions like `getFirebaseMessagingLibNoThrow()` and `getExpoNotificationsLib()` before accessing optional peer dependencies
Applied to files:
packages/react-native-sdk/expo-config-plugin/src/withAndroidManifest.tspackages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.ts
📚 Learning: 2026-01-09T11:07:38.535Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/**/*.kt : When adding Android native functionality, create Kotlin file in `android/src/main/java/com/streamvideo/reactnative/`, use `ReactMethod` annotation, register in `StreamVideoReactNativePackage.kt`, and call from TypeScript via `NativeModules.StreamVideoReactNative`
Applied to files:
packages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/util/CallAliveServiceChecker.ktpackages/react-native-sdk/src/utils/StreamVideoRN/types.tspackages/react-native-sdk/src/utils/keepCallAliveHeadlessTask.tspackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.ktpackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/keepalive/StreamCallKeepAliveHeadlessService.ktpackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/keepalive/KeepAliveNotification.kt
📚 Learning: 2026-01-09T11:07:38.535Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/**/*.tsx : Always request media permissions via `usePermissionRequest()` hook before calling device enable methods like `call.camera.enable()` or `call.microphone.enable()`
Applied to files:
packages/react-native-sdk/android/src/main/AndroidManifest.xmlpackages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.tspackages/react-native-sdk/android/src/main/AndroidManifestNew.xml
📚 Learning: 2026-01-09T11:07:38.535Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/theme/**/*.ts : Apply deep partial theme overrides using the `DeepPartial<Theme>` type when customizing StreamVideo provider theme to maintain type safety
Applied to files:
packages/react-native-sdk/src/utils/StreamVideoRN/types.ts
📚 Learning: 2026-01-09T11:08:35.312Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T11:08:35.312Z
Learning: Applies to packages/{client,react-sdk,react-native-sdk}/src/**/*.ts?(x) : Make public API surfaces explicit with TypeScript types and interfaces
Applied to files:
packages/react-native-sdk/src/utils/StreamVideoRN/types.ts
📚 Learning: 2026-01-09T11:07:38.535Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/hooks/push/**/*.ts : Use RxJS subjects from `src/utils/push/internal/rxSubjects.ts` (like `pushTappedIncomingCallCId$`, `pushAcceptedIncomingCallCId$`, `pushRejectedIncomingCallCId$`, `voipPushNotificationCallCId$`) to bridge native push events to React hooks
Applied to files:
packages/react-native-sdk/src/utils/StreamVideoRN/types.tspackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.ktpackages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.ts
📚 Learning: 2026-01-12T11:59:18.251Z
Learnt from: santhoshvai
Repo: GetStream/stream-video-js PR: 2038
File: packages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/audio/utils/AudioFocusUtil.kt:37-48
Timestamp: 2026-01-12T11:59:18.251Z
Learning: In packages/react-native-sdk Android audio utilities (specifically AudioFocusUtil.kt), it's acceptable to use the !! (force unwrap) operator when accessing WebRTCModule via reactContext.getNativeModule(), as a fatal crash is the preferred behavior if the module is not registered.
Applied to files:
packages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.kt
📚 Learning: 2026-01-09T11:07:38.535Z
Learnt from: CR
Repo: GetStream/stream-video-js PR: 0
File: packages/react-native-sdk/CLAUDE.md:0-0
Timestamp: 2026-01-09T11:07:38.535Z
Learning: Applies to packages/react-native-sdk/src/providers/**/*.tsx : Use the renderless component pattern (component that returns null) for side-effect-only child components within `StreamCall` and `StreamVideo` providers to keep logic separated and testable
Applied to files:
packages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.ts
🧬 Code graph analysis (1)
packages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.ts (2)
packages/react-native-sdk/src/utils/keepCallAliveHeadlessTask.ts (1)
keepCallAliveCallRef(15-17)packages/client/src/store/CallState.ts (1)
callingState(752-754)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Code Lint, Unit Test and dogfood versioning
- GitHub Check: test-and-build
🔇 Additional comments (16)
packages/react-native-sdk/src/utils/StreamVideoRN/types.ts (2)
8-16: LGTM! Clean, minimal type definitions for keep-alive configuration.These new types appropriately capture only the required fields (
id,name,title,body) rather than depending on the fullAndroidChanneltype from Notifee. This decouples the foreground service configuration from the Notifee library.Note: The
AndroidChannelimport on line 6 is still needed forcallChannelandincomingCallChannelin the push notification config.
155-171: Configuration type update aligns with the new SDK-owned service.The simplified
KeepAliveAndroidChannelConfigandKeepAliveAndroidNotificationTextstypes are structurally compatible with existing code that may have passed fullAndroidChannelobjects, since TypeScript uses structural typing and the new types require only a subset of properties.packages/react-native-sdk/src/utils/keepCallAliveHeadlessTask.ts (1)
8-17: Well-documented ref pattern for headless task communication.The module-level ref with explicit documentation about process death limitations is a pragmatic approach. The comment correctly notes that killed-state support would require a different architecture.
packages/react-native-sdk/src/index.ts (1)
11-11: LGTM! Side-effect import for headless task registration.The import triggers task registration at SDK initialization. The
keepCallAliveHeadlessTaskmodule internally guards withPlatform.OS !== 'android', so this is safe on all platforms.packages/react-native-sdk/android/src/main/AndroidManifest.xml (1)
8-14: Service declaration is correct; permissions are properly delegated to the consuming app.The service attributes are appropriate:
exported="false"prevents external accessstopWithTask="true"ensures the service stops when the user dismisses the appforegroundServiceType="mediaPlayback|camera|microphone"correctly matches the service capabilitiesThe manifest correctly omits
FOREGROUND_SERVICE_*andPOST_NOTIFICATIONSpermissions—these are properly handled at the app level. The Expo config plugin automatically addsFOREGROUND_SERVICE_CAMERA,FOREGROUND_SERVICE_MICROPHONE, andPOST_NOTIFICATIONSto consuming apps. Runtime permission requests viauseAndroidKeepCallAliveEffect()handle the optionalFOREGROUND_SERVICE_MEDIA_PLAYBACK. Notification channels are created before service startup inKeepAliveNotification.kt.packages/react-native-sdk/expo-config-plugin/src/withAndroidManifest.ts (2)
46-63: LGTM! New keep-alive service declaration is well-structured.The service configuration correctly defines the
StreamCallKeepAliveHeadlessServicewith appropriateforegroundServiceTypevalues for media playback, camera, and microphone. Thetools:replaceattribute ensures the foreground service type properly overrides any inherited values.
75-94: Clean separation of concerns between Notifee and SDK keep-alive services.The logic correctly:
- Adds Notifee service only for ringing push notifications (with
shortServicetype)- Adds SDK-owned keep-alive service separately when
androidKeepCallAliveis enabledThis separation aligns with the PR objective of replacing Notifee for keep-alive while preserving its use for ringing notifications.
packages/react-native-sdk/android/src/main/AndroidManifestNew.xml (1)
8-12: Service declaration looks correct.The service is properly configured with:
exported="false"- prevents external accessstopWithTask="true"- ensures cleanup when app is killed- Appropriate
foregroundServiceTypefor media/camera/microphonepackages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.kt (2)
134-159: LGTM! Service start method is well-structured.The implementation correctly:
- Uses
ContextCompat.startForegroundServicefor backward compatibility- Handles exceptions and rejects the promise with descriptive error
- Follows the coding guidelines by using
@ReactMethodannotationOne consideration: the promise resolves immediately before the service actually starts its foreground notification. This is acceptable as the service has a few seconds to call
startForeground(), but be aware that if the service fails to do so, the app may ANR without the JS side knowing.
164-173: LGTM! Service stop method is clean and handles errors properly.packages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.ts (1)
27-39: LGTM! Permission check is correctly implemented.The logic properly:
- Bypasses the check for Android versions below 13 (API 33)
- Uses
PermissionsAndroid.check(read-only) rather than requesting- Logs appropriately when permission is not granted
This aligns with the coding guidelines for automatic permission handling for POST_NOTIFICATIONS on Android 13+.
packages/react-native-sdk/android/src/main/java/com/streamvideo/reactnative/keepalive/StreamCallKeepAliveHeadlessService.kt (5)
21-42: Well-structured foreground service initialization.The implementation correctly calls
startForegroundbefore delegating to the superclass, which prevents ANR issues when starting foreground services. Defensive null handling with defaults for all extras is appropriate. As per learnings, creating the notification channel before building the notification is the correct approach.
44-56: Correct HeadlessJS task configuration.Returning
nullwhencallCidis missing prevents invalid task execution. The unbounded timeout (0) withallowedInForeground=trueis appropriate for long-running call tasks.
63-81: Correct foreground service type computation with permission checks.The implementation properly checks runtime permissions before adding
CAMERAandMICROPHONEforeground service types, which is required on Android 14+. UsingMEDIA_PLAYBACKas the baseline is appropriate for keeping calls alive in the background.
83-89: Proper version-aware foreground service start.The compatibility wrapper correctly uses the 3-parameter
startForegroundoverload on Android Q+ while falling back to the 2-parameter version for older APIs.
91-133: Well-organized companion object with proper intent builders.Constants are appropriately scoped (public for API, private for internal defaults). Intent builders are clean and follow standard patterns. Task name
"StreamVideoKeepCallAlive"correctly matches the TypeScript headless task registration inkeepCallAliveHeadlessTask.ts.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
...id/src/main/java/com/streamvideo/reactnative/keepalive/StreamCallKeepAliveHeadlessService.kt
Show resolved
Hide resolved
...native-sdk/android/src/main/java/com/streamvideo/reactnative/util/CallAliveServiceChecker.kt
Outdated
Show resolved
Hide resolved
packages/react-native-sdk/src/hooks/useAndroidKeepCallAliveEffect.ts
Outdated
Show resolved
Hide resolved
| return NotificationCompat.Builder(context, channelId) | ||
| .setContentTitle(title) | ||
| .setContentText(body) | ||
| .setOngoing(true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can use NotificationCompat.CallStyle.forOngoingCall for creating notification style. this will make notifications for call alive and telecom consistent.
💡 Overview
Previously we used Notifee for the foreground service to keep the call alive when app goes to background. Now this foreground service is added to our SDK.
Summary by CodeRabbit
New Features
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.