Skip to content

Conversation

@Brazol
Copy link
Contributor

@Brazol Brazol commented Jan 23, 2026

resolves FLU-362

When back button is used to leave the app on Android the app enteres into a detached state where the Flutter Activity is detached but Flutter engine is still running. This caused isses when handling ringing notifications and accepting the call from this state.

Summary by CodeRabbit

  • New Features

    • Exposed app lifecycle state to improve lifecycle-aware behavior.
  • Bug Fixes

    • Fixed accepting incoming calls and call notifications when the app is in a detached (Android back-button) state.
    • Prevented duplicate initialization of push notification and audio-interruption handlers on repeated logins.
    • Avoided clearing activity context prematurely on Android plugin detach.
  • Chores

    • Added null-safe handling when reading stored active-call data.

✏️ Tip: You can customize this high-level summary in your review settings.

@Brazol Brazol requested a review from a team as a code owner January 23, 2026 12:28
@coderabbitai
Copy link

coderabbitai bot commented Jan 23, 2026

📝 Walkthrough

Walkthrough

Adds app lifecycle state to client state, records app lifecycle in StreamVideo, ensures one-time initialization of push-notification and audio-interruption observers in the dogfooding app, adds Android detached-state guards for accepting calls, and applies minor Android push-notification null-safety and lifecycle tweaks; changelogs updated.

Changes

Cohort / File(s) Summary
App initialization (dogfooding)
dogfooding/lib/app/app_content.dart
Adds _isInitialized guard to ensure push-notification manager and audio-interruption observers run only once per login; resets flag on logout and moves _handleMobileAudioInterruptions into push-notification init flow.
Client lifecycle state
packages/stream_video/lib/src/core/client_state.dart
Adds public appLifecycleState getter to ClientState and final MutableStateEmitter<LifecycleState?> appLifecycleState to MutableClientState, initialized with MutableStateEmitterImpl(null).
Lifecycle recording & call accept guard
packages/stream_video/lib/src/stream_video.dart
Writes app lifecycle into appLifecycleState in _onAppState; observeCallAcceptRingingEvent now skips _onCallAccept on Android when lifecycle is detached.
Android push-notification null-safety
packages/stream_video_push_notification/android/src/main/kotlin/.../SharedPreferencesUtils.kt
Uses a default empty JSON array ("[]") when stored string is null before parsing active calls.
Android plugin lifecycle cleanup
packages/stream_video_push_notification/android/src/main/kotlin/.../StreamVideoPushNotificationPlugin.kt
onDetachedFromActivity() stops clearing context; only activity is cleared.
Changelogs
packages/stream_video_flutter/CHANGELOG.md, packages/stream_video_push_notification/CHANGELOG.md
Adds Android-specific upcoming fixes about accepting incoming calls and notifications when app is in detached state.

Sequence Diagram

sequenceDiagram
    participant App as App Lifecycle
    participant StreamVideo as StreamVideo Client
    participant ClientState as ClientState
    participant CallHandler as Call Accept Handler
    participant Android as Android Platform

    App->>StreamVideo: _onAppState(newState)
    StreamVideo->>ClientState: appLifecycleState.value = newState

    Android->>StreamVideo: observeCallAcceptRingingEvent(event)
    StreamVideo->>ClientState: read appLifecycleState
    alt state == detached (Android)
        ClientState-->>StreamVideo: detached
        StreamVideo->>StreamVideo: skip _onCallAccept
    else state != detached
        ClientState-->>StreamVideo: not detached
        StreamVideo->>CallHandler: _onCallAccept(event)
        CallHandler->>Android: accept incoming call
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • renefloor
  • xsahil03x

Poem

🐇 I hopped through lifecycle trees tonight,
One init only—now setup's right,
Rings found even when Android's gone,
Notifications wake at dawn.
🥕📞

🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description is minimal and lacks several required template sections including Goal, Implementation details, UI Changes, Testing, and Contributor Checklist. Complete the PR description using the provided template. Add Goal, Implementation details, Testing explanation, and verify Contributor Checklist items are addressed.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main fix: addressing call ringing issues on Android when the app is in detached state.
Linked Issues check ✅ Passed The PR addresses the Android detached state issue by adding lifecycle state tracking, implementing platform-specific guards for call acceptance, and fixing context management in native code.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the Android detached state issue: lifecycle state management, call acceptance guards, context cleanup, and null-safety improvements.

✏️ 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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link

codecov bot commented Jan 23, 2026

Codecov Report

❌ Patch coverage is 16.66667% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 6.47%. Comparing base (213945a) to head (4e55c44).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
packages/stream_video/lib/src/stream_video.dart 0.00% 5 Missing ⚠️
Additional details and impacted files
@@          Coverage Diff          @@
##            main   #1161   +/-   ##
=====================================
  Coverage   6.47%   6.47%           
=====================================
  Files        601     601           
  Lines      42025   42030    +5     
=====================================
+ Hits        2721    2722    +1     
- Misses     39304   39308    +4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/stream_video/lib/src/core/client_state.dart (1)

97-104: Reset appLifecycleState during clear() to avoid stale detached state.
If the last value is detached, a subsequent login could keep that value until the next lifecycle emission, potentially skipping accept handling. Consider nulling it on clear (Line 100).

🛠️ Suggested fix
  Future<void> clear() async {
    activeCalls.value = [];
    outgoingCall.value = null;
+   appLifecycleState.value = null;
    connection.value = ConnectionState.disconnected(user.value.id);
  }

@Brazol Brazol merged commit 51cc267 into main Jan 29, 2026
16 checks passed
@Brazol Brazol deleted the fix/android-ringing-detached branch January 29, 2026 13:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants