Skip to content

Bugfix/1688/fix call background death#6334

Open
mahibi wants to merge 25 commits into
masterfrom
bugfix/1688/fixCallBackgroundDeath
Open

Bugfix/1688/fix call background death#6334
mahibi wants to merge 25 commits into
masterfrom
bugfix/1688/fixCallBackgroundDeath

Conversation

@mahibi

@mahibi mahibi commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

🏁 Checklist

  • ⛑️ Tests (unit and/or integration) are included or not needed
  • 🔖 Capability is checked or not needed
  • 🔙 Backport requests are created or not needed: /backport to stable-xx.x
  • 📅 Milestone is set
  • 🌸 PR title is meaningful (if it should be in the changelog: is it meaningful to users?)

🤖 AI (if applicable)

  • The content of this PR was partly or fully generated using AI

@mahibi mahibi self-assigned this Jun 11, 2026
@mahibi mahibi added the 2. developing Work in progress label Jun 11, 2026
Tarek Loubani added 25 commits June 11, 2026 14:47
…round, with notification controls for managing the call

- Add CallForegroundService with persistent notification
- Support calls in background without requiring picture-in-picture mode
- Add "Return to call" and "End call" action buttons to CallForegroundService notification with corresponding PendingIntent
- Handle proper foreground service types for microphone/camera permissions
- Add notification permission and fallback messaging.
- Add EndCallReceiver to handle end call broadcasts from notification action
- Use existing ic_baseline_close_24 drawable for end call action icon
- Register broadcast receiver in CallActivity to handle end call requests from notification using ReceiverFlag.NotExported for Android 14+ compatibility
- Add proper cleanup flow: notification action → EndCallReceiver → CallActivity → proper hangup sequence
- Track intentional call leaving to prevent unwanted service restarts
- Release proximity sensor lock properly during notification-triggered hangup
- Add diagnostic logging throughout the end call flow for debugging

The implementation follows Android best practices:
- Uses NotExported receiver flag for internal app-only broadcasts
- Properly unregisters receivers in onDestroy to prevent leaks
- Uses immutable PendingIntents for security
- Maintains proper state management during call termination

Signed-off-by: Tarek Loubani <tarek@tarek.org>
…tyle

Signed-off-by: Tarek Loubani <tarek@tarek.org>
Signed-off-by: Tarek Loubani <tarek@tarek.org>
Signed-off-by: Tarek Loubani <tarek@tarek.org>
Signed-off-by: Tarek Loubani <tarek@tarek.org>
Signed-off-by: Tarek Loubani <tarek@tarek.org>
Signed-off-by: Tarek Loubani <tarek@tarek.org>
Signed-off-by: Tarek Loubani <tarek@tarek.org>
…do a rapid gesture switch back.

For the quick-switch gesture and the recents-to-chat path, the OS starts animating the transition before onPause() fires. By the time onPause()
runs, the window has already been moved off-screen by the gesture animation, so enterPictureInPictureMode() silently fails — Android requires the
window to still be visible.

Why onTopResumedActivityChanged(false) fixes it:
This callback fires when any other activity (including ChatActivity in the same app) takes the "top resumed" slot. Critically, it fires before
onPause() and before any transition animation begins — the window is still fully on-screen. enterPictureInPictureMode() succeeds at this point.

Why back-button worked but this didn't:
Back button goes through OnBackPressedCallback.handleOnBackPressed() synchronously, which calls enterPipMode() before any transition, not in a
lifecycle callback. onTopResumedActivityChanged puts the task-switch path on the same footing.

API compatibility: On API 26–28, onTopResumedActivityChanged is never called by the system (it didn't exist in Activity before API 29), so
onPause() remains the fallback. Older devices primarily use button navigation and won't have the gesture quick-switch anyway.

Signed-off-by: Tarek Loubani <tarek@tarek.org>
Use observeForever for leaveRoom observer so cleanup runs even when
activity is paused. Move ApplicationWideCurrentRoomHolder.clear() into
the leave success callback to avoid premature state clearing. Guard
against double leaveRoom calls with isLeavingRoom flag.

Signed-off-by: Tarek Loubani <tarek@tarek.org>
…c logging

- Prevent spurious roomJoined events from re-running performCall() when
  already IN_CONVERSATION, fixing call reconnection when ChatActivity
  resumes behind PIP or task switch
- Remove setAutoEnterEnabled(true) which conflicts with manual
  enterPictureInPictureMode() calls causing invisible PIP windows
- Set aspect ratio in initial PIP params (onCreate) so PIP params are
  always valid
- Add isInPipMode guard to onUserLeaveHint to prevent redundant PIP
  entry attempts
- Add diagnostic logging to CallBaseActivity lifecycle methods and
  CallActivity PIP/call state transitions
- Add unit tests documenting PIP race conditions and leaveRoom
  lifecycle behavior

Signed-off-by: Tarek Loubani <tarek@tarek.org>
…tivityChanged fallback

The previous approach had three competing PIP entry mechanisms on API 31+
(auto-enter, onTopResumedActivityChanged, onPause) that raced against each
other, and onTopResumedActivityChanged toggled setAutoEnterEnabled off/on
which broke smooth transitions.

New layered approach per the Android PIP documentation:
- API 31+: setAutoEnterEnabled(true) as primary for home/recents gestures
- API 29+: onTopResumedActivityChanged as fallback (fires while window is
  still visible, catches quick-switch gestures auto-enter misses)
- API 26-30: onUserLeaveHint for home/recents, onPause fallback for 26-28
- All APIs: OnBackPressedCallback for back gesture (only manual entry point)

Key fix: onTopResumedActivityChanged no longer disables auto-enter. It checks
isInPictureInPictureMode() so if auto-enter already handled it, the manual
call is skipped. No races, no toggling.

Also removes shouldFinishOnStop, pipFallbackHandler, topResumedLostTime, and
onCreateTime which were artifacts of the old racing approach.

Signed-off-by: Tarek Loubani <tarek@tarek.org>
Remove excludeFromRecents=true from CallActivity manifest entry. This
attribute caused Android to destroy the entire call task ~5s after the
user navigated away via task switch, killing the call.

Guard all teardown in onDestroy (signaling listeners, localStream,
foreground service, proximity sensor, broadcast receiver) so that
system-initiated destruction during task switching doesn't tear down
active call resources. The foreground service keeps the process alive.

Simplify onTopResumedActivityChanged to only enter PIP on API 29-30.
On API 31+, auto-enter handles swipe-up; onUserLeaveHint moves the task
to back as a safety net for task switching.

Signed-off-by: Tarek Loubani <tarek@tarek.org>
Use Android CallStyle notification (API 31+) to show green status bar
chip with call duration timer, matching the native phone app experience.
Falls back to standard notification on older API levels.

The notification is updated every second via startForeground() to keep
the call duration accurate, using callStartTime from
ApplicationWideCurrentRoomHolder.

Signed-off-by: Tarek Loubani <tarek@tarek.org>
…uent calls

Start foreground service at the beginning of prepareCall() before heavy
initialization, stop it in hangup() and unconditionally in onDestroy(),
cancel stale periodic handlers in onStartCommand(), and reset
callStartTime between calls to prevent state leakage.

Signed-off-by: Tarek Loubani <tarek@tarek.org>
…space, generic catch)

- Break long log lines to respect 120 char limit
- Remove unused imports (LiveData, assertFalse)
- Remove trailing whitespace
- Merge duplicate test to reduce class function count below threshold
- Catch IllegalArgumentException instead of generic Exception
- Ensure EndCallReceiver.kt ends with newline

Signed-off-by: Tarek Loubani <tarek@tarek.org>
Signed-off-by: Tarek Loubani <tarek@tarek.org>
Signed-off-by: Tarek Loubani <tarek@tarek.org>
Signed-off-by: Tarek Loubani <tarek@tarek.org>
Signed-off-by: Tarek Loubani <tarek@tarek.org>
…ervice

Signed-off-by: Tarek Loubani <tarek@tarek.org>
…ervice

Signed-off-by: Tarek Loubani <tarek@tarek.org>
Signed-off-by: Tarek Loubani <tarek@tarek.org>
Signed-off-by: Tarek Loubani <tarek@tarek.org>
… keys

Adds Gradle distribution key (1BD97A6A) for gradle-9.5.1-src.zip and
regenerates verification metadata for org.jetbrains.kotlin.plugin.compose
2.3.21 and other updated dependencies.

Also removes stray closing brace in ChatActivity.

AI-assistant: OpenCode (deepseek-v4-pro)
Signed-off-by: Tarek Loubani <tarek@tarek.org>
@github-actions

Copy link
Copy Markdown
Contributor

APK file: https://github.com/nextcloud/talk-android/actions/runs/27347821297/artifacts/7570066996
To test this change/fix you can simply download above APK file and install and test it in parallel to your existing Nextcloud app.
qrcode (please click on link to get QR code displayed)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

continue call when minimizing app and PIP is not available/enabled

1 participant