cometchat-android-v6-calls — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited cometchat-android-v6-calls (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Ground truth:com.cometchat:chatuikit-{compose,kotlin}-android:6.x(+calls-sdk-android:5.x) — resolved AAR (javap) +ui-kit/android/v6. Official docs: https://www.cometchat.com/docs/calls/android/overview · Docs MCP:claude mcp add --transport http cometchat-docs https://www.cometchat.com/docs/mcp(or fetch the URL directly without MCP). Verify symbols against the installed package/source before relying on them.
Validated end-to-end on Pixel 3 (Android 12) ↔ Next.js peer on 2026-05-12. All five must be applied — the V6 calls artifacts ship without them and the app crashes on first call attempt without one of them in place. (V6 is GA since 2026-05-25; GA software can still need these workarounds — they were validated against the 6.0.0 line and are not yet confirmed removed on later patches.)
calls-sdk-android:5.0.+ is a REQUIRED peer depThe V6 chatuikit advertises bundled calling, but its compose AAR references com.cometchat.calls.core.CometChatCalls$SessionSettingsBuilder at bytecode level — that class lives in calls-sdk-android:5.0.0, not in the chatuikit AAR. Without this dep, Application.onCreate crashes with ClassNotFoundException.
implementation("com.cometchat:chatuikit-compose-android:6.0.+")
implementation("com.cometchat:calls-sdk-android:5.0.+") // REQUIREDannotations-java5 duplicate-class excludeBuild fails with Duplicate class org.jetbrains.annotations.* from a transitive legacy dep.
configurations.all {
exclude(group = "org.jetbrains", module = "annotations-java5")
}chat-sdk-android's CallManager bytecode references legacy com.cometchat.calls.{CometChatRTCView, model.RTCUser, model.RTCReceiver, model.RTCCallback} (V3-era paths). calls-sdk-android:5.0.0 moved everything to com.cometchat.calls.core.* and dropped these. Without stubs in your source tree, the first call attempt fires E/CallManager: CometChat Calling module not found.
Create empty stubs at the legacy paths:
// app/src/main/java/com/cometchat/calls/CometChatRTCView.java
package com.cometchat.calls;
public class CometChatRTCView {}
// app/src/main/java/com/cometchat/calls/model/RTCUser.java
package com.cometchat.calls.model;
public class RTCUser {
public RTCUser(String uid, String name, String avatar) {}
}
// app/src/main/java/com/cometchat/calls/model/RTCReceiver.java
package com.cometchat.calls.model;
public class RTCReceiver {
public RTCReceiver(String uid, String name, String type) {}
}
// app/src/main/java/com/cometchat/calls/model/RTCCallback.java
package com.cometchat.calls.model;
public interface RTCCallback<T> { void onSuccess(T result); }Class verification finds these locally and lets CallManager load. They're never actually invoked at runtime because the V6 chatuikit uses com.cometchat.calls.core.CometChatCalls.startSession (a different code path) for the real call surface.
CometChatCallButtons — wire your ownThe kit's CometChatCallButtons(user = user) composable IGNORES the per-row user prop and dials whichever user was first rendered (it captures global state on first composition). Symptom: every call regardless of which row you tap rings the same person. Workaround:
@Composable
fun UserRow(user: User) {
val context = LocalContext.current
Row(...) {
Text(user.name ?: user.uid)
IconButton(onClick = {
val outgoing = Call(
user.uid,
CometChatConstants.RECEIVER_TYPE_USER, // see W5 — order matters
CometChatConstants.CALL_TYPE_VIDEO,
)
CometChat.initiateCall(outgoing, object : CometChat.CallbackListener<Call>() {
override fun onSuccess(call: Call) {
// Hand off to the kit's outgoing-call screen — this part works correctly
CometChatCallActivity.Companion.launchOutgoingCallScreen(context, call, null)
}
override fun onError(e: CometChatException) { /* surface */ }
})
}) { Text("📹") }
}
}CometChatCallActivity.launchOutgoingCallScreen handles the full lifecycle (ringing UI, token mint, joinSession, transition to in-call surface) correctly — only the button composable is broken.
Call constructor arg order CHANGED in chat-sdk 5.x// ❌ v4 style — server returns ERR_BAD_REQUEST: "Failed to validate the data sent with the request"
Call(receiverUid, CALL_TYPE_VIDEO, RECEIVER_TYPE_USER)
// ✅ v5 (what chatuikit-compose:6.0.0 pulls in transitively as chat-sdk-android:5.0.1)
Call(receiverUid, RECEIVER_TYPE_USER, CALL_TYPE_VIDEO)Bytecode-confirmed against chat-sdk-android:5.0.1: arg1 → receiverUid, arg2 → receiverType, arg3 → type.
Production-grade voice + video calling for native Android v6 (stable, GA 2026-05-25). Loaded by cometchat-calls when android_version === "v6". Routes to the Compose or Kotlin Views sub-flow based on the surface the project uses (already determined by cometchat-android-v6-core from the presence of androidx.compose.ui:ui / compose.material3 in the dependency graph).
⚠️ Important — V6 still needs `calls-sdk-android` on the classpath despite marketing claims. The V6 chatuikit packages advertise "bundled calling," but at runtime CometChatUIKit.init references com.cometchat.calls.core.CometChatCalls$SessionSettingsBuilder — a class that lives in com.cometchat:calls-sdk-android, NOT in the chatuikit AAR. Without the peer dep, the app crashes on Application.onCreate with ClassNotFoundException. Always add:
dependencies {
implementation("com.cometchat:chatuikit-compose-android:6.0.+") // or chatuikit-kotlin-android
implementation("com.cometchat:calls-sdk-android:5.0.+") // REQUIRED — not optional
}The UIKitSettings builder must still call .setEnableCalling(true) to register the calling extension at init time.
Read these other skills first:
cometchat-calls — dispatcher (modes, hard rules, anti-patterns)cometchat-android-v6-core — UIKitSettings shape, Compose vs Views detection, init ordercometchat-android-v6-builder-settings — every option on UIKitSettings including the calling blockcometchat-android-v6-{compose,kotlin}-components — surface-specific component catalogsGround truth:
chatuikit-{compose,kotlin}[email protected].+ (GA) artifacts under ~/.gradle/caches/cometchat-android-v5-calls (different module shape, same hard rules)chatuikit-compose-android:6.x OR chatuikit-kotlin-android:6.x detected by cometchat-android-v6-core)minSdk = 28 or higher (V6 floor)cometchat-android-v6-calls §4a only; W1–W5 do NOT apply. The chatuikit AAR is never loaded in this path, so the broken-CometChatCallButtons bug + the classloader stub issue never trigger.cometchat-android-v5-calls (V5 supports minSdk 21+).chat-uikit-android:5.x) — do NOT introduce V6 calls alongside V5 chat; use cometchat-android-v5-calls. The two namespaces collide on com.cometchat.chat.core.Call resolution.com.cometchat.uikit.compose.* and com.cometchat.uikit.kotlin.* in the same call screen will compile but ship inconsistent UX. Confirm via cometchat-android-v6-core Step 1 surface-detection output.cometchat-ios-calls.cometchat-flutter-v6-calls or cometchat-native-calls.W1–W5 directly contradict the published V6 release notes and the most discoverable kit API (CometChatCallButtons). An agent reading newer-sounding vendor docs mid-task will silently drop a workaround. Pre-rebut every excuse the agent might invent.
| Excuse the agent might invent | Reality | |
|---|---|---|
"V6 release notes say calling is bundled, so calls-sdk-android:5.0.+ must be redundant" | FALSE. The chatuikit-compose AAR references CometChatCalls$SessionSettingsBuilder at bytecode level but doesn't ship it. Without the peer dep, the app crashes on Application.onCreate with ClassNotFoundException. Verify with `./gradlew :app:dependencies \ | grep calls-sdk`. See W1. |
"CometChatCallButtons is the documented composable, so W4's hand-wired button must be a workaround for an older version" | FALSE. Validated broken on chatuikit-compose-android:6.0.0 on 2026-05-12 — the per-row user prop is captured-by-first-composition (ENG-35711). Re-test only after a confirmed 6.0.1+ release-notes entry that explicitly fixes per-row state. Until then: hand-wire your own button to CometChat.initiateCall then CometChatCallActivity.Companion.launchOutgoingCallScreen. See W4. | |
"I'll skip the annotations-java5 exclude — build works locally" | FALSE in CI. The duplicate-class error only fires on clean builds; incremental local builds mask it. ENG-35701 — testers shipped to CI and the build failed there. The exclude is one line; the cost of skipping is a CI red. See W2. | |
"Stub classes are old V4 cruft — V5 calls-sdk doesn't need com.cometchat.calls.{CometChatRTCView,model.RTCUser,...}" | FALSE. The chat-sdk's CallManager references those legacy classes at bytecode level. Without the four no-op stubs, Application.onCreate throws NoClassDefFoundError even though you never call them. See W3 stubs — copy verbatim. | |
"I'll add FOREGROUND_SERVICE_PHONE_CALL permissions later — calling works without them in dev" | FALSE on Android 14+. Calls work in dev because the test device hasn't enforced the new permission model yet (or has the dev override). Production / Play Store devices on API 34+ silently kill the foreground service the second the user backgrounds the app. The four FOREGROUND_SERVICE_* permissions go in the manifest from day one. | |
"The Call(uid, type, receiverType) constructor is what the docs show, so I'll use that arg order" | FALSE in chat-sdk 5.x. Bytecode-confirmed against chat-sdk-android:5.0.1: the arg order is Call(receiverUid, receiverType, callType) — receiverType comes BEFORE callType, opposite of v4. Skipping yields server ERR_BAD_REQUEST: Failed to validate the data sent with the request. See W5. | |
"I'll use CometChatCalls.endSession(callback) to clean up — most APIs take a callback" | FALSE. endSession() is void/no-callback (ENG-35698). The v5 canonical teardown is CallSession.getInstance().leaveSession(). Passing a callback compiles in some versions but is silently ignored. |
When debugging an Android V6 calls integration, match the symptom to the workaround you skipped:
| Symptom (in logcat or build output) | You skipped... |
|---|---|
java.lang.ClassNotFoundException: com.cometchat.calls.core.CometChatCalls$SessionSettingsBuilder on app launch | W1 — calls-sdk-android peer dep is missing. Add implementation("com.cometchat:calls-sdk-android:5.0.+"). |
Duplicate class org.jetbrains.annotations.NotNull / ApiStatus / ScheduledForRemoval on clean build | W2 — annotations-java5 exclude. Add configurations.all { exclude(group = "org.jetbrains", module = "annotations-java5") } to app/build.gradle.kts. |
java.lang.NoClassDefFoundError: com.cometchat.calls.CometChatRTCView (or RTCUser / RTCReceiver / RTCCallback) on Application.onCreate | W3 — the four legacy no-op stub classes. Copy verbatim from the §"Five required workarounds" W3 block. |
| Every call-button row dials the same person regardless of which row was tapped | W4 — you used CometChatCallButtons instead of hand-wiring. The per-row user prop is captured-by-first-composition. Switch to manual CometChat.initiateCall + CometChatCallActivity.Companion.launchOutgoingCallScreen. |
Server returns ERR_BAD_REQUEST: Failed to validate the data sent with the request on initiateCall | W5 — Call() constructor arg order is v4-style. Switch to Call(receiverUid, receiverType, callType). |
| Foreground service silently dies when user backgrounds the app on Android 14+ | The four FOREGROUND_SERVICE_* permissions are missing from AndroidManifest.xml. Add FOREGROUND_SERVICE, FOREGROUND_SERVICE_PHONE_CALL, FOREGROUND_SERVICE_MICROPHONE, FOREGROUND_SERVICE_CAMERA. |
| Outgoing call rings on the peer but never joins after accept | The accept→join handoff isn't wired. The onIncomingCallReceived listener must call CometChat.acceptCall THEN CometChatCalls.joinSession — and the receiver app needs the same workaround chain (W1–W5) to play back. |
endSession() takes 0 args error | You passed a callback. v5 CometChatCalls.endSession() is void. For teardown with state, use CallSession.getInstance().leaveSession(). |
grep -nE "implementation.*calls-sdk-android" app/build.gradle.kts returns ≥ 1 match (W1).grep -nE 'exclude.*annotations-java5' app/build.gradle.kts returns ≥ 1 match (W2).grep -rnE "class (CometChatRTCView|RTCUser|RTCReceiver|RTCCallback)" app/src/main/java/com/cometchat/calls/ returns 4 matches — the W3 stub classes are in place.grep -nE "Call\((\w+),\s*CometChatConstants.RECEIVER_TYPE_" app/src/ confirms RECEIVER_TYPE_ is the SECOND arg (W5 — receiverType before callType).AndroidManifest.xml declares all four FOREGROUND_SERVICE_* permissions../gradlew :app:assembleDebug cleanly — no duplicate-class, no ClassNotFoundException, no compile errors.The same seven non-negotiables from the dispatcher; v6 changes the how but not the what.
✅ The additive UI-Kit path does NOT call `CometChatCalls.login`. When you use the V6 UI Kit (the common case —CometChatIncomingCall+ the auto call buttons inCometChatMessageHeader, with.setEnableCalling(true)), the kit registers the calling extension at init and chains the Calls-SDK auth offCometChatUIKit.loginfor you. Both canonical Android v6 sample apps wire calls end-to-end with ZERO `CometChatCalls.login` (verified: noCometChatCalls.logininsample-app-kotlin/sample-app-compose). Adding it yourself on the UI-Kit path is redundant. (Matches the standing finding: UI Kit login chains Calls-SDK login; the explicit step only fires on raw-SDK paths.)
`CometChatCalls.login(uid, AUTH_KEY, ...)` is required ONLY on the STANDALONE / raw-Calls-SDK path — when you call CometChatCalls.generateToken / startSession directly without the UI Kit's calling components. There, the Calls SDK has its own auth state separate from the Chat SDK: after CometChat.login(uid, AUTH_KEY) succeeds, also call CometChatCalls.login(uid, AUTH_KEY, ...) — without it the first raw calls API call throws "auth token cannot be null".
import com.cometchat.calls.core.CometChatCalls
import com.cometchat.calls.exceptions.CometChatException as CallsException
import com.cometchat.calls.model.CallUser // ← callback type, NOT chat User
// ✓ RIGHT — chat login first, then calls login
CometChat.login(uid, AUTH_KEY, object : CometChat.CallbackListener<User>() {
override fun onSuccess(user: User) {
CometChatCalls.login(uid, AUTH_KEY,
object : CometChatCalls.CallbackListener<CallUser>() {
override fun onSuccess(callUser: CallUser) { /* both ready */ }
override fun onError(e: CallsException) { /* surface */ }
})
}
override fun onError(e: CometChatException) { /* surface */ }
})Surprises (verified on real hardware, Android 12 + 14):
com.cometchat.chat.models.User does NOT expose authToken on Android — don't try user.authToken. Use the (uid, apiKey) overload for dev or fetch the auth token from your backend for production.com.cometchat.calls.model.CallUser, NOT com.cometchat.chat.models.User. Importing the wrong type gives "Type mismatch" at compile time.CometChat.getLoggedInUser() returns a non-null user.V6 still routes ringing through Chat SDK (CometChat.initiateCall) and the WebRTC session through the Calls SDK — but both are accessed via the unified V6 facade. The two-Call-classes problem from V5 still exists internally; the V6 components hide it but custom code that imports com.cometchat.chat.core.Call directly must still pick the right one.
// ⚠️ DO NOT USE — broken at chatuikit-compose:6.0.0 (see W4 above).
// Captures first-rendered user globally; every row dials the same person.
// CometChatCallButtons(user = user, group = null)
// ✓ RIGHT — wire your own button + use the kit's outgoing-call Activity directly.
// See §"Five required workarounds" W4 for the full pattern.
IconButton(onClick = {
val call = Call(user.uid, RECEIVER_TYPE_USER, CALL_TYPE_VIDEO) // see W5 — arg order
CometChat.initiateCall(call, object : CometChat.CallbackListener<Call>() {
override fun onSuccess(c: Call) {
CometChatCallActivity.Companion.launchOutgoingCallScreen(context, c, null)
}
override fun onError(e: CometChatException) { /* surface */ }
})
}) { Text("📹") }Identical to V5 (rule 1.2 in cometchat-android-v5-calls). The V6 UIKit doesn't ship its own ConnectionService — you write one. Reference implementation in cometchat-android-v5-calls/references/voip-calling.md works unchanged for V6 (the FCM payload shape and ConnectionService API are platform-level, not SDK-version-specific).
⚠️ Mandatory exclude. A transitive dep of chatuikit-compose-android:6.0.+ pulls in the legacy org.jetbrains:annotations-java5:17.0.0, which conflicts with the modern org.jetbrains:annotations:23.0.0 brought in by Kotlin 2.0+. AGP fails the build with dozens of Duplicate class org.jetbrains.annotations.* lines. Add to app/build.gradle.kts:
configurations.all {
exclude(group = "org.jetbrains", module = "annotations-java5")
}The exclude must be on configurations.all (not on a specific configuration) because the legacy artifact leaks into runtime, compile, and androidTest classpaths.
V6 ships its own CometChatOngoingCallService registered automatically via the kit's manifest merge. You still must declare the Android 14+ FOREGROUND_SERVICE_PHONE_CALL / FOREGROUND_SERVICE_MICROPHONE / FOREGROUND_SERVICE_CAMERA permissions in your app's manifest — manifest merge does NOT pull permissions across module boundaries.
<!-- AndroidManifest.xml — required even though the service is kit-provided -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" />Unchanged from V5 / chat dispatcher — see cometchat-android-v6-production for the token-endpoint pattern.
The V6 CometChatOngoingCall composable / Kotlin View handles the camera-light / mic-release cleanup via its own DisposableEffect (Compose) or onDetachedFromWindow (Views). Custom OngoingCall surfaces (Section 5) must replicate this — the hard rule still applies, just the canonical implementation is in the kit.
Same set as V5, plus V6's minSdk = 28 floor means POST_NOTIFICATIONS runtime prompt (Android 13+) is always required. The V6 kit ships a CallPermissionsHandler that runs the standard request flow with rationale strings.
V6 exposes CometChatIncomingCall as a top-level composable / View. In standalone mode, mount it inside setContent { ... } at the root of your MainActivity, OUTSIDE the navigation graph, so it survives screen transitions.
// MainActivity.kt — Compose, standalone mode
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
CometChatTheme {
Box(modifier = Modifier.fillMaxSize()) {
AppNavigation() // Your nav graph (calls or otherwise)
CometChatIncomingCall(modifier = Modifier.fillMaxSize()) // overlays everything
}
}
}
}
}In Kotlin Views, the equivalent is a top-level FrameLayout in the Activity's layout XML containing both the host <fragment> and <com.cometchat.uikit.kotlin.presentation.incomingcall.CometChatIncomingCall>.
V6 has no separate calls module. If chatuikit-{compose,kotlin}-android is already in app/build.gradle.kts from cometchat-android-v6-core, calls are already on the classpath. The skill only:
UIKitSettings: val settings = UIKitSettings.UIKitSettingsBuilder()
.setAppId(BuildConfig.COMETCHAT_APP_ID)
.setRegion(BuildConfig.COMETCHAT_REGION)
.setAuthKey(BuildConfig.COMETCHAT_AUTH_KEY)
.subscribePresenceForAllUsers()
.setEnableCalling(true) // ← v6 flips calling on here (real method: setEnableCalling)
.build()AndroidManifest.xml.cometchat-android-v6-troubleshooting: Activity themes hosting V6 Views must inherit from CometChatTheme.DayNight (V6 components extend MaterialCardView and reference kit-specific theme attrs that aren't in Theme.AppCompat.* or Theme.MaterialComponents.*). Compose surfaces are immune.Detailed V6 init order: cometchat-android-v6-core. UIKitSettings option-by-option: cometchat-android-v6-builder-settings.
Both surfaces ship the same five call components with the same parameter names. Surface determines which import you use.
com.cometchat.uikit.compose.presentation.<component>.ui.*)Real namespace iscom.cometchat.uikit.compose.presentation.{incomingcall,callbuttons,ongoingcall,outgoingcall,calllogs}.ui.*(NOTcom.cometchat.chatuikit.calling.*— that package does not exist). Use the exact per-component import fromcometchat-android-v6-compose-components.
| Composable | Purpose |
|---|---|
CometChatCallButtons(user, group) | Voice + video buttons — typically in a top-bar trailing slot or contact card |
CometChatIncomingCall(modifier) | Root-mounted overlay; renders nothing when no call active |
CometChatOutgoingCall(call, user, group) | Pushed when local user initiates; auto-dismisses on accept/reject |
CometChatOngoingCall(callSettingsBuilder, sessionId) | WebRTC view — handles camera/mic/end controls |
CometChatCallLogs(onItemClick) | Paginated history; integrates with Compose Navigation |
com.cometchat.uikit.kotlin.presentation.<component>.*)Same names, different package — real namespace com.cometchat.uikit.kotlin.presentation.{incomingcall,callbuttons,ongoingcall.ui,outgoingcall,calllogs}.* (NOT com.cometchat.chatuikit.calling.*). Use the exact per-component import from cometchat-android-v6-kotlin-components. Inflate via XML or programmatically:
<com.cometchat.uikit.kotlin.presentation.callbuttons.CometChatCallButtons
android:id="@+id/callButtons"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />Then in code: binding.callButtons.setUser(user).
Full component-by-component catalogs live in the existing cometchat-android-v6-compose-components and cometchat-android-v6-kotlin-components skills — read whichever matches the project's surface.
When product === "voice-video" and there is no V6 chat integration yet.
Split by calling mode:
Calls SDK ONLY. NO chatuikit-android, NO ConnectionService, NO FCM-for-VoIP. Same SDK as V5 (com.cometchat.calls-sdk-android). Scaffold:
CometChatCalls.init(...) ONLY. No chatuikit, no Chat SDK init.setContent with NavHost for /, /meet/{sessionId}.AndroidView factory wrapping RelativeLayout (remember-stable), LaunchedEffect(sessionId) fires CometChatCalls.joinSession(sessionId, settings, container, CallbackListener), DisposableEffect cleanup. See references/call-session.md.FOREGROUND_SERVICE_MICROPHONE/CAMERA + CometChatOngoingCallService registration. NO ConnectionService.https://yourapp.com/meet/<sessionId> deep-link routing.Why no chatuikit / no ConnectionService: session mode never touches kit components or push. The W1–W5 V6 workarounds (which are for chatuikit's broken integration with the Calls SDK) DO NOT apply to standalone session-only — they're only relevant when the V6 kit is loaded.
Dual-SDK + telecom + push + V6 chatuikit:
MainActivity with setContent that holds: nav graph (with /profile, /calls, /ongoing-call/{sessionId} routes), CometChatIncomingCall overlay (rule 1.7), top-level theme with CometChatTheme. Profile screen has CometChatCallButtons next to the user's name.MainActivity extending AppCompatActivity with theme CometChatTheme.DayNight, a FragmentContainerView for nav + a sibling CometChatIncomingCall view in the same FrameLayout. Profile fragment hosts CometChatCallButtons.-keep class com.cometchat.** { *; }).When chat is already integrated via V6. The skill:
.setEnableCalling(true) to the existing UIKitSettings.UIKitSettingsBuilder() chain.FOREGROUND_SERVICE_* permissions to manifest.CometChatIncomingCall at the root of the existing Activity (Compose: in setContent; Views: in the root layout XML).CometChatMessageHeader (V6) already renders them; the kit calls initiateCall automatically when calling is enabled.chatuikit-{compose,kotlin}-android:6.0.0 bytecode-references CometChatCalls.SessionSettingsBuilder, which ships ONLY in com.cometchat:calls-sdk-android:5.0.+. Without that explicit dependency the app crashes at runtime (NoClassDefFoundError). .setEnableCalling(true) alone is NOT enough. (What you must NOT add is the separate V5 calls UI Kit — that's the module that conflicts; the bare calls-sdk-android peer dep is required.)MaterialCardView and crash with Failed to resolve attribute at index N if hosted in Theme.AppCompat.*. Compose surfaces are not affected. Already documented in cometchat-android-v6-troubleshooting; surfaced here because calls components are the canary that exposes the bug.SessionType.VOICE and the V6 CallType.AUDIO are not interchangeable enums. If you import from com.cometchat.calls.types.SessionType, you're pulling V5; V6 uses CallType from the unified UIKit package.chatuikit-compose-android OR chatuikit-kotlin-android (NOT both) in app/build.gradle.kts — V6 picks one surface.setEnableCalling(true) on UIKitSettings.UIKitSettingsBuilder()CometChatTheme.DayNight (Kotlin Views only)FOREGROUND_SERVICE_* permissions in AndroidManifest.xmlCometChatIncomingCall mounted at root (Compose: outside nav graph; Views: top-level FrameLayout)Application.onCreatereferences/advanced-features.md — Recording, Picture-in-Picture, Screen-share (receive) — source-verified against calls-sdk-android 5.xcometchat-android-v5-calls/references/ — VoIP push, foreground service, ConnectionService, FCM payload shape — all unchanged on V6cometchat-android-v6-builder-settings — every UIKitSettings option including calling block detailscometchat-android-v6-{compose,kotlin}-components — full surface-specific component catalogscometchat-android-v6-production — token endpoints, ProGuard rulescometchat-android-v6-troubleshooting — V6 Kotlin Views theme parent crash diagnostic~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.