Skip to content

docs(android): ringing through the Calls SDK and Push Notifications SDK - #561

Open
hritika-cometchat wants to merge 9 commits into
mainfrom
feature/android-ringing-push-sdk
Open

hritika-cometchat wants to merge 9 commits into
mainfrom
feature/android-ringing-push-sdk

Conversation

@hritika-cometchat

@hritika-cometchat hritika-cometchat commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Android calling no longer signals through the Chat SDK. The Calls SDK 5.1 creates, joins and ends calls; the Push Notifications SDK 2.0 calls module rings the device in every app state (foreground, background, killed); the UI Kit hosts the screens. This PR updates every Android page that described the old flow and adds the two pages the new flow needs.

Consumer-facing wording is "ringing" and "legacy ringing"; the pages never say v1 or v2.

Calls SDK (calls/android/)

  • ringing.mdx rewritten: Calls SDK-only flow with a sequence diagram, CometChatCalls.initiateCall, prepared-session events ("ringing…" / answered), addIncomingCallListener with the reason table, answer from the answer activity, decline, cancel, ring timeout, end with leave(), call waiting, group calls, logout, status values.
  • voip-calling.mdx rewritten as Push Ringing (slug kept, no redirect): dependencies, PNConfiguration setter table, three-line FCM service, answer activity, permissions and ensureRingReady / getDiagnostics / verifyPushSetup, how a ring ends, call during a call, missed calls, killed-app behaviour, staging hosts, tokens, own incoming-call screen, theming resources, MANUAL mode, troubleshooting.
  • migrating-from-legacy-ringing.mdx (new, in the Migration Guide nav group): before/after diagrams, seven migration steps, a 16-row method mapping table, caller and callee screens before/after, checklist.
  • setup: 5.1 version, push dependencies, one-shot init warning. events: getActiveSession, onParticipantConnected, prepared-session semantics, Incoming Call and Login listener sections. actions, overview, custom-control-panel: leave(). migration-guide-v5: 5.0 → 5.1 section. troubleshooting: six ringing rows.

UI Kit (ui-kit/android/)

  • calling-integration.mdx rewritten: five steps (dependencies, setEnableCalling, push config with setAnswerActivity(CometChatOngoingCallActivity), permissions, logout), what the kit does from there, own-screen calls, ring-screen colours, upgrade pointer.
  • ongoing-call.mdx (new, in the Components nav): the in-call screen and Push SDK answer activity.
  • call-features, incoming-call (deprecated, kept for setIncomingCallActivity), outgoing-call (call states, endReason, ViewModel members), call-buttons, call-logs updated for the new flow.
  • Smaller edits: getting-started, getting-started-kotlin/-jetpack (no extra dependency, 6.1.0), methods (new settings, logout behaviour), sound-manager, troubleshooting (16 calling rows), llms-android-v6, upgrading-from-v5 (Ringing table), color-resources (six cometchat_pn_call_* resources).

Notifications and Chat SDK

  • notifications/android-push-notifications.mdx rewritten for Push SDK 2.0: automatic tokens, PNConfiguration, inline reply and tap listener, badge count kept app-side; VoIP/ConnectionService and manual-token sections removed.
  • sdk/android/v5/calling-overview and v5/real-time-listeners: notes that the Chat SDK calling APIs and CallListener are superseded by the Calls SDK (deprecation lands with a coming Chat SDK release).

Before merging

  • Versions are placeholders for the public releases: calls-sdk-android:5.1.0, push-notifications-android / push-notifications-calls-android:2.0.0, UI Kit 6.1.0. Do not merge before they are published.
  • Confirm the published UI Kit POM exposes the Calls and Push SDKs as api (Getting Started and Calling Integration say no extra dependency is needed).
  • Confirm the public path of sample-app-kotlin-push / sample-app-compose-push; the notifications page links to the repository root.
  • The pages say the Chat SDK calling APIs are "superseded; a coming Chat SDK release marks them deprecated". Once the Chat SDK release with the @Deprecated annotations ships, change that wording to "deprecated".
  • The new Ongoing Call page has no screenshot yet.
  • Rendered pass with mint dev (links verified by file existence only).

Related: ENG-39907.

🤖 Generated with Claude Code

…cations SDK

Android calling no longer signals through the Chat SDK. The Calls SDK 5.1
creates, joins and ends calls; the Push Notifications SDK 2.0 calls module
rings the device in every app state; the UI Kit hosts the screens.

Calls SDK
- Rewrite ringing.mdx for the Calls SDK-only flow (initiateCall, prepared
  session events, IncomingCallListener, answer/decline/cancel/end, group calls)
- Rewrite voip-calling.mdx as "Push Ringing" (PNConfiguration, FCM service,
  answer activity, readiness, busy, missed calls, own ring screen, MANUAL)
- Add migrating-from-legacy-ringing.mdx with the method-by-method mapping
- setup: 5.1 version, host overrides, push dependencies, one-shot init
- events: getActiveSession, onParticipantConnected, incoming-call and login
  listeners; actions/overview/custom-control-panel: leave(); migration guide:
  5.0 to 5.1 section; troubleshooting rows

UI Kit
- Rewrite calling-integration.mdx; add ongoing-call.mdx (answer activity)
- call-features, incoming-call (deprecated), outgoing-call, call-buttons,
  call-logs updated for the new flow
- getting-started, methods, sound-manager, troubleshooting, llms, upgrading
  and color-resources edits (no extra dependency, logout, ring-screen colours)

Notifications: rewrite android-push-notifications.mdx for Push SDK 2.0.
Chat SDK v5: deprecation notes on calling-overview and the Call Listener.
docs.json: two new nav entries.

Versions are the planned public releases (calls 5.1.0, push 2.0.0,
UI Kit 6.1.0); hold the merge until they are published.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@mintlify

mintlify Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
cometchat 🟢 Ready View Preview Oct 20, 2026, 2:49 PM

💡 Tip: Enable Automations to automatically generate PRs for you.

… from Ringing

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… SDK calling is superseded not deprecated, real call event names, getting-started parity
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…DK internals

The UI Kit has no Push SDK dependency, so the answer activity is a small app class
that builds the call with CallRingingUtils.buildIncomingCall and opens
CometChatOngoingCallActivity. Fix incoming-call to use real APIs. Remove MANUAL mode,
token registrar options, diagnostics, decline-queue and identifier details.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…omingCallTheme)

The Push SDK's incoming-call screen can now be themed in code, light and
dark, and the UI Kit can pass its own theme to it. The docs still said
there was no runtime theme API and listed six colour resources.

- Push Ringing: setIncomingCallTheme in the setter table; the theming
  section now covers CometChatPNIncomingCallTheme (Mode, Colors, Kotlin
  and Java), saving across a killed process, the theme -> resource ->
  default order, and all eleven colour resources with their setters.
  Notes that the class is not the @style/CometChatPNIncomingCallTheme
  window style.
- Push Notifications: setIncomingCallTheme row.
- UI Kit calling integration: CometChatTheme.getIncomingCallTheme() and
  Compose incomingCallTheme(), the app's mapping function, the one-line
  setIncomingCallTheme, and which UI Kit colour feeds each field.
- Color resources: eleven colours with the UI Kit colour, light and dark.
- Incoming Call (deprecated): CometChatIncomingCallStyle -> theme field
  map, including what has no equivalent.
- Call features: incoming call paragraph.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Checked every page in this PR against calls-core prepare-session-flow
(Calls SDK 5.1.0-beta.2), push-notifications-sdk-android release/2.0
(2.0.0-beta.3) and uikit-android ENG-39907-ringing-v2-incoming.

Dependencies and setup
- The UI Kit brings the Calls SDK only; no library module depends on the
  Push SDK. Getting Started (3 pages), Call Features and Calling
  Integration now say so, and Calling Integration's Gradle snippets add
  both push artifacts (UI Kit listed first, so its ring colours win).
- UI Kit minSdk is 28, not 26.
- Permissions: RECORD_AUDIO, CAMERA and POST_NOTIFICATIONS already merge
  in from the Calls SDK, the UI Kit and the calls module; pages now say
  "request at runtime" instead of "declare".
- Push init runs in Application.onCreate on every start, before login:
  login/logout token registration only runs in a process where init ran.
- setProviderId is required; setNotificationSmallIcon covers chat
  notifications only and defaults to a system icon.
- Logout: a Chat logout unregisters the token; only a Calls logout stops
  a ring.

Calls SDK
- getActiveSession() is @nullable: Kotlin samples use ?. and the page
  explains registering after join or through CallSession.getInstance().
- A prepared session that expires (5 min) reports onConnectionClosed, not
  onSessionTimedOut; samples and tables updated.
- Callee end reasons include `ended`; treat unknown reasons as "over".
- joinSession ignores settings on a prepared session (callee settings are
  the Push SDK's).
- The caller has no ring timer: recommend one, since nothing else ends a
  ring the callee never received for 5 minutes.
- initiateCall accepts RECEIVER_TYPE_GROUP; group decline/busy is local.
- A second init() with a different app ID re-initialises.
- CometChatCallsConstants has been deprecated since 5.0.

Push ringing samples
- setShowWhenLocked/setTurnScreenOn guarded for API 27 (calls module
  minSdk is 26).
- The answer activity is no longer singleTop in the manifest, and
  onNewIntent relaunches with FLAG_ACTIVITY_NEW_TASK only, as the UI
  Kit's CometChatOngoingCallActivity does; singleTop routed the relaunch
  back to the same instance.
- Custom ring screen gets its manifest entry.

UI Kit events
- CometChatCallEvent.CallRejected fires only for End or the 45 s timer;
  CallEnded only when this device hangs up a call opened with a Call.
- Compose CometChatIncomingCall: onAcceptClick runs after the default
  accept; use onAcceptRequested to answer through the Push SDK.
- setOnError / onError take one parameter.
- CometChatCallActivity cannot be the Push SDK's incoming-call activity.
- initiateUserCall fails with CALL_IN_PROGRESS; ACTIVE_CALL is Call
  Buttons'.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e-check

docs(android): correct the ringing pages against the SDK source (for #561)

@honey-cometchat honey-cometchat left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The answer-activity samples call setShowWhenLocked / setTurnScreenOn (API 27+) without a working fallback, while the pages say minSdk 26:

  • In ringing.mdx the calls are unguarded, so the sample crashes on Android 8.0.
  • In voip-calling.mdx they're guarded, but nothing covers API 26.

The suggestions below copy the pattern the Push SDK already uses in its own ring screen (IncomingCallActivity.showOverKeyguard()): setShowWhenLocked on 27+, FLAG_SHOW_WHEN_LOCKED | FLAG_TURN_SCREEN_ON on 26.

Comment thread calls/android/ringing.mdx
Comment on lines +292 to +293
setShowWhenLocked(true)
setTurnScreenOn(true)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Calling setShowWhenLocked / setTurnScreenOn directly crashes on Android 8.0 (NoSuchMethodError) and fails lint (NewApi). Both methods are API 27+, and this page says minSdk 26.

The Push SDK's own ring screen guards them and falls back to window flags on API 26 (IncomingCallActivity.kt, showOverKeyguard()). Suggest doing the same here:

Suggested change
setShowWhenLocked(true)
setTurnScreenOn(true)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setShowWhenLocked(true)
setTurnScreenOn(true)
} else {
@Suppress("DEPRECATION")
window.addFlags(
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
)
}

Comment thread calls/android/ringing.mdx
Comment on lines +308 to +309
setShowWhenLocked(true);
setTurnScreenOn(true);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same issue in the Java tab: both methods are API 27+, so this crashes on Android 8.0.

Suggested change
setShowWhenLocked(true);
setTurnScreenOn(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setShowWhenLocked(true);
setTurnScreenOn(true);
} else {
getWindow().addFlags(
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
}

Comment on lines +165 to 168
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { // the manifest attributes cover 27+
setShowWhenLocked(true)
setTurnScreenOn(true)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The version check is right, but the comment isn't. The android:showWhenLocked / android:turnScreenOn manifest attributes are also API 27+, so on Android 8.0 nothing puts this screen over the lock screen. Suggest adding the window-flag fallback, as the Push SDK's own IncomingCallActivity does:

Suggested change
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { // the manifest attributes cover 27+
setShowWhenLocked(true)
setTurnScreenOn(true)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setShowWhenLocked(true)
setTurnScreenOn(true)
} else {
@Suppress("DEPRECATION")
window.addFlags(
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
)
}

The one-line versions at lines 329 and 363 need the same else branch.

Comment on lines +203 to 206
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { // the manifest attributes cover 27+
setShowWhenLocked(true);
setTurnScreenOn(true);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same as the Kotlin tab: add the API 26 fallback.

Suggested change
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { // the manifest attributes cover 27+
setShowWhenLocked(true);
setTurnScreenOn(true);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setShowWhenLocked(true);
setTurnScreenOn(true);
} else {
getWindow().addFlags(
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
}

@honey-cometchat honey-cometchat left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The caller's answer handler can join the session more than once. onParticipantJoined fires again for each group member who answers, for a callee who reconnects, and for an answer that arrives after a cancel or timeout. A second joinSession rejoins the caller mid-call.

The inline suggestions add one ringing flag, shared by the join handler, Cancel and Ring timeout. With it, the caller joins once, and only while the call is still ringing. It also replaces the answered variable the Ring timeout sample uses but never declares.

Comment thread calls/android/ringing.mdx
Comment on lines +167 to +171
// The callee answered: now the caller joins.
override fun onParticipantJoined(participant: Participant) {
if (participant.uid == me) return
joinCallSession(call.sessionId, call.type)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

onParticipantJoined can fire more than once, and joinSession has no "already joined" check:

  • Group calls: it fires for every member who answers.
  • 1:1 reconnect: it fires again if the callee drops and rejoins.
  • Echoed events: participant events can be delivered again once the caller is in the call.
  • Late answer: it can arrive after the caller cancelled or timed out.

A second joinSession doesn't find the prepared session (the first join used it), so it fetches a new token and mounts a second call view, which drops and rejoins the caller mid-call.

Suggest a ringing flag on the activity (private var ringing = true, set when initiateCall succeeds), so the caller joins once and only while the call is still ringing:

Suggested change
// The callee answered: now the caller joins.
override fun onParticipantJoined(participant: Participant) {
if (participant.uid == me) return
joinCallSession(call.sessionId, call.type)
}
// The callee answered: now the caller joins. This can fire again (another
// group member answers, the callee reconnects, or an answer arrives after a
// cancel or timeout), so join only once and only while still ringing.
override fun onParticipantJoined(participant: Participant) {
if (participant.uid == me || !ringing) return
ringing = false
joinCallSession(call.sessionId, call.type)
}

The Cancel and Ring timeout samples then use the same flag (see the comments there).

Comment thread calls/android/ringing.mdx
Comment on lines +198 to +203
// The callee answered: now the caller joins.
@Override
public void onParticipantJoined(Participant participant) {
if (participant.getUid().equals(me)) return;
joinCallSession(call.getSessionId(), call.getType());
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same in the Java tab. ringing must be a field here, because a local can't be changed from inside the anonymous listener (private boolean ringing = true;).

Suggested change
// The callee answered: now the caller joins.
@Override
public void onParticipantJoined(Participant participant) {
if (participant.getUid().equals(me)) return;
joinCallSession(call.getSessionId(), call.getType());
}
// The callee answered: now the caller joins. This can fire again (another
// group member answers, the callee reconnects, or an answer arrives after a
// cancel or timeout), so join only once and only while still ringing.
@Override
public void onParticipantJoined(Participant participant) {
if (participant.getUid().equals(me) || !ringing) return;
ringing = false;
joinCallSession(call.getSessionId(), call.getType());
}

Comment thread calls/android/ringing.mdx
Log.d(TAG, "Joined call session")
}

fun cancelOutgoingCall(sessionId: String) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Following on from the join guard: set ringing = false at the start of a cancel. That way an answer that lands after the cancel is ignored, which is what the note below this sample asks for. The code currently doesn't do it.

Suggested change
fun cancelOutgoingCall(sessionId: String) {
fun cancelOutgoingCall(sessionId: String) {
if (!ringing) return // already answered, cancelled or timed out
ringing = false // a late onParticipantJoined is now ignored

Comment thread calls/android/ringing.mdx
@Override
public void onError(CometChatException e) {
Log.e(TAG, "Failed to join: " + e.getMessage());
void cancelOutgoingCall(String sessionId) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same for the Java tab:

Suggested change
void cancelOutgoingCall(String sessionId) {
void cancelOutgoingCall(String sessionId) {
if (!ringing) return; // already answered, cancelled or timed out
ringing = false; // a late onParticipantJoined is now ignored

Comment thread calls/android/ringing.mdx
<Tab title="Kotlin">
```kotlin
handler.postDelayed({
if (!answered) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

answered isn't declared or set anywhere on the page. Using the same ringing flag fixes two things:

  • The timer becomes a no-op once the call is answered.
  • A timeout that fires after the caller already cancelled no longer sends a second endCall with unanswered.
Suggested change
if (!answered) {
if (ringing) {
ringing = false

Comment thread calls/android/ringing.mdx
<Tab title="Java">
```java
handler.postDelayed(() -> {
if (!answered) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same for the Java tab:

Suggested change
if (!answered) {
if (ringing) {
ringing = false;

This branch was successfully deployed

1 active deployment
staging — 2fcdc6a5 Deployed Oct 20, 2026 by mintlify[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants