Skip to content

chore(ui): improved Android PiP implementation #1003

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

Merged
merged 11 commits into from
Jul 2, 2025

Conversation

Brazol
Copy link
Contributor

@Brazol Brazol commented Jul 1, 2025

Resolves FLU-178, FLU-174
Part of FLU-173

🎯 Goal

Reworked Android PiP implementation to avoid other widgets overlapping the picture-in-picture video track. PiP mode is now triggered from a native Android side and will show a dedicated overlay on the Flutter side.

Simple migration is required to make PiP work on Android.

screen-20250701-161136.mp4

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Introduced automatic Picture-in-Picture (PiP) support for Android video calls that activates when the app is backgrounded or the home button is pressed.
    • Added new Android PiP widgets: AndroidPipOverlay and StreamPictureInPictureAndroidView for improved PiP video presentation.
    • Developers should now extend StreamFlutterActivity or StreamFlutterFragmentActivity instead of FlutterActivity to enable built-in PiP support.
  • Bug Fixes

    • Improved PiP overlay to ensure correct video layout and prevent interference from other UI elements.
  • Deprecations

    • Manual PiP enable/disable methods and lifecycle-based PiP management are deprecated in favor of automatic PiP handling.
  • Documentation

    • Updated migration instructions and changelog to reflect the new automatic PiP integration and usage.

@Brazol Brazol marked this pull request as ready for review July 1, 2025 13:20
@Brazol Brazol requested a review from a team as a code owner July 1, 2025 13:20
Copy link

coderabbitai bot commented Jul 1, 2025

"""

Walkthrough

This update refactors Android Picture-in-Picture (PiP) support in the video call Flutter package. It introduces a new StreamFlutterActivity for automatic PiP handling, removes manual PiP controls and lifecycle hooks, adds new Flutter widgets for PiP overlays, and deprecates old PiP API methods in favor of a more integrated, channel-based approach.

Changes

File(s) Change Summary
dogfooding/android/app/src/main/kotlin/.../MainActivity.kt Changed base class to StreamFlutterActivity, removed PiP logic and onUserLeaveHint() override.
packages/stream_video_flutter/CHANGELOG.md Documented new PiP approach, added migration steps, and announced deprecations.
packages/stream_video_flutter/android/src/main/kotlin/.../MethodCallHandlerImpl.kt Removed handling for PiP enable/disable method calls and related imports.
packages/stream_video_flutter/android/src/main/kotlin/.../StreamFlutterActivity.kt Added new abstract class for automatic Android PiP support, with lifecycle overrides.
packages/stream_video_flutter/android/src/main/kotlin/.../StreamFlutterFragmentActivity.kt Added new abstract class extending FlutterFragmentActivity with automatic PiP support.
packages/stream_video_flutter/android/src/main/kotlin/.../PictureInPictureHelper.kt Refactored for channel-based PiP control, added new methods, deprecated old entry method, removed preference checks.
packages/stream_video_flutter/lib/src/call_screen/call_content/call_content.dart Removed all manual PiP state logic and lifecycle hooks; PiP overlay now integrated directly.
packages/stream_video_flutter/lib/src/call_screen/call_content/picture_in_picture/android_pip_overlay.dart Added new AndroidPipOverlay widget for PiP video rendering.
packages/stream_video_flutter/lib/src/call_screen/call_content/picture_in_picture/stream_picture_in_picture_android_view.dart Added new widget for managing PiP state and communication with native Android.
packages/stream_video_flutter/lib/stream_video_flutter.dart Exported new Android PiP overlay and view widgets.
packages/stream_video_flutter/lib/stream_video_flutter_background.dart Removed deprecated setPictureInPictureEnabled method.
packages/stream_video_flutter/lib/stream_video_flutter_method_channel.dart Removed deprecated setPictureInPictureEnabled method override and native calls.
packages/stream_video_flutter/lib/stream_video_flutter_platform_interface.dart Removed deprecated setPictureInPictureEnabled method declaration.

Sequence Diagram(s)

sequenceDiagram
    participant FlutterApp
    participant StreamFlutterActivity
    participant PictureInPictureHelper
    participant AndroidSystem

    FlutterApp->>StreamFlutterActivity: App starts (extends StreamFlutterActivity)
    StreamFlutterActivity->>PictureInPictureHelper: configureFlutterEngine()
    PictureInPictureHelper->>FlutterApp: Setup MethodChannel for PiP control

    FlutterApp->>PictureInPictureHelper: setPictureInPictureAllowed (via channel)
    PictureInPictureHelper-->>FlutterApp: Updates PiP allowed state

    StreamFlutterActivity->>PictureInPictureHelper: onUserLeaveHint() or onPause()
    PictureInPictureHelper->>AndroidSystem: Request enterPictureInPictureMode if allowed

    AndroidSystem-->>StreamFlutterActivity: Notify onPictureInPictureModeChanged
    StreamFlutterActivity->>PictureInPictureHelper: notifyPictureInPictureModeChanged()
    PictureInPictureHelper->>FlutterApp: Notify PiP mode state via channel

    FlutterApp->>AndroidPipOverlay: Show/hide overlay based on PiP mode
Loading

Assessment against linked issues

Objective Addressed Explanation
Fix Android PiP behavior when another screen is open (FLU-178) PiP is now managed automatically via StreamFlutterActivity and StreamPictureInPictureAndroidView, improving multi-screen handling.
Prevent overlay widgets from showing instead of video track in Android PiP (FLU-174) Added AndroidPipOverlay widget ensures correct video content is displayed during PiP.
General PiP improvements and fixes including lifecycle and state management (FLU-173) Refactored PiP logic to use channel-based control, deprecated manual methods, and integrated PiP state in widgets.

Assessment against linked issues: Out-of-scope changes

No out-of-scope changes detected related to the linked issues.

Poem

🐇
A hop, a skip, PiP takes flight,
Now handled for you, day or night!
No more manual calls or fuss,
Just overlay magic—leave the rest to us.
With channels and widgets, the video’s in view,
Flutter and Android, PiP made new!
🌟
"""


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f71a02a and 619b07b.

📒 Files selected for processing (4)
  • packages/stream_video_flutter/android/src/main/kotlin/io/getstream/video/flutter/stream_video_flutter/StreamFlutterActivity.kt (1 hunks)
  • packages/stream_video_flutter/android/src/main/kotlin/io/getstream/video/flutter/stream_video_flutter/StreamFlutterFragmentActivity.kt (1 hunks)
  • packages/stream_video_flutter/android/src/main/kotlin/io/getstream/video/flutter/stream_video_flutter/service/PictureInPictureHelper.kt (2 hunks)
  • packages/stream_video_flutter/lib/src/call_screen/call_content/picture_in_picture/android_pip_overlay.dart (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/stream_video_flutter/lib/src/call_screen/call_content/picture_in_picture/android_pip_overlay.dart
  • packages/stream_video_flutter/android/src/main/kotlin/io/getstream/video/flutter/stream_video_flutter/StreamFlutterFragmentActivity.kt
  • packages/stream_video_flutter/android/src/main/kotlin/io/getstream/video/flutter/stream_video_flutter/StreamFlutterActivity.kt
  • packages/stream_video_flutter/android/src/main/kotlin/io/getstream/video/flutter/stream_video_flutter/service/PictureInPictureHelper.kt
⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: analyze_legacy_version
  • GitHub Check: stream_video_push_notification
  • GitHub Check: stream_video_screen_sharing
  • GitHub Check: stream_video_noise_cancellation
  • GitHub Check: stream_video
  • GitHub Check: analyze
  • GitHub Check: build
  • GitHub Check: stream_video_flutter
✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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

🧹 Nitpick comments (6)
packages/stream_video_flutter/lib/src/call_screen/call_content/picture_in_picture/android_pip_overlay.dart (1)

23-40: Consider simplifying widget hierarchy and state management.

The implementation is solid, but there are two minor optimization opportunities:

  1. Redundant layout widgets: SizedBox.expand and Positioned.fill both expand to fill available space. Consider using just SizedBox.expand or removing the Positioned.fill wrapper.

  2. State management: The widget extends StatefulWidget but doesn't appear to have any mutable state. Consider using StatelessWidget unless state management is planned for future enhancements.

-class AndroidPipOverlay extends StatefulWidget {
+class AndroidPipOverlay extends StatelessWidget {
   const AndroidPipOverlay({
     super.key,
     required this.call,
     this.sort,
     this.customBuilder,
   });

   final Call call;
   final Comparator<CallParticipantState>? sort;
   final CallWidgetBuilder? customBuilder;

   @override
-  State<AndroidPipOverlay> createState() => _AndroidPipOverlayState();
-}
-
-class _AndroidPipOverlayState extends State<AndroidPipOverlay> {
-  @override
   Widget build(BuildContext context) {
     return Material(
       color: Colors.black,
       child: SizedBox.expand(
-        child: Positioned.fill(
-          child: widget.customBuilder?.call(context, widget.call) ??
+        child: customBuilder?.call(context, call) ??
             StreamCallParticipants(
-              call: widget.call,
+              call: call,
               layoutMode: ParticipantLayoutMode.pictureInPicture,
-              sort: widget.sort,
+              sort: sort,
             ),
-        ),
       ),
     );
   }
 }
dogfooding/android/app/src/main/kotlin/io/getstream/video/flutter/dogfooding/MainActivity.kt (2)

24-24: Remove unnecessary empty line.

     override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
         super.configureFlutterEngine(flutterEngine)
-        
         MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->

24-24: Remove trailing whitespace.

-        super.configureFlutterEngine(flutterEngine)
-        
+        super.configureFlutterEngine(flutterEngine)
+
packages/stream_video_flutter/android/src/main/kotlin/io/getstream/video/flutter/stream_video_flutter/StreamFlutterActivity.kt (2)

50-50: Remove trailing whitespace.

-} 
+}

24-26: Consider improving lambda clarity.

The lambda { this } could be more explicit for better readability.

-        PictureInPictureHelper.initializeWithFlutterEngine(flutterEngine) { this }
+        PictureInPictureHelper.initializeWithFlutterEngine(flutterEngine) { 
+            this@StreamFlutterActivity 
+        }
packages/stream_video_flutter/lib/src/call_screen/call_content/picture_in_picture/stream_picture_in_picture_android_view.dart (1)

140-166: Consider using null-safe operators for better defensive programming.

While the current guards ensure _overlayEntry won't be null, using null-safe operators would make the code more robust against future changes.

-    overlay.insert(_overlayEntry!);
+    _overlayEntry?.let { overlay.insert(it) };
     _isOverlayVisible = true;
-    _overlayEntry!.remove();
+    _overlayEntry?.remove();
     _overlayEntry = null;
     _isOverlayVisible = false;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d245042 and e4a7455.

📒 Files selected for processing (12)
  • dogfooding/android/app/src/main/kotlin/io/getstream/video/flutter/dogfooding/MainActivity.kt (1 hunks)
  • packages/stream_video_flutter/CHANGELOG.md (1 hunks)
  • packages/stream_video_flutter/android/src/main/kotlin/io/getstream/video/flutter/stream_video_flutter/MethodCallHandlerImpl.kt (1 hunks)
  • packages/stream_video_flutter/android/src/main/kotlin/io/getstream/video/flutter/stream_video_flutter/StreamFlutterActivity.kt (1 hunks)
  • packages/stream_video_flutter/android/src/main/kotlin/io/getstream/video/flutter/stream_video_flutter/service/PictureInPictureHelper.kt (2 hunks)
  • packages/stream_video_flutter/lib/src/call_screen/call_content/call_content.dart (2 hunks)
  • packages/stream_video_flutter/lib/src/call_screen/call_content/picture_in_picture/android_pip_overlay.dart (1 hunks)
  • packages/stream_video_flutter/lib/src/call_screen/call_content/picture_in_picture/stream_picture_in_picture_android_view.dart (1 hunks)
  • packages/stream_video_flutter/lib/stream_video_flutter.dart (1 hunks)
  • packages/stream_video_flutter/lib/stream_video_flutter_background.dart (1 hunks)
  • packages/stream_video_flutter/lib/stream_video_flutter_method_channel.dart (1 hunks)
  • packages/stream_video_flutter/lib/stream_video_flutter_platform_interface.dart (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: build
  • GitHub Check: analyze
  • GitHub Check: stream_video_screen_sharing
  • GitHub Check: stream_video_noise_cancellation
  • GitHub Check: stream_video_push_notification
  • GitHub Check: stream_video_flutter
  • GitHub Check: stream_video
🔇 Additional comments (27)
packages/stream_video_flutter/lib/stream_video_flutter.dart (1)

29-31: LGTM: Well-organized exports for new PiP components.

The new exports are properly placed among other Picture-in-Picture related components and follow the consistent export format used throughout the file.

packages/stream_video_flutter/lib/stream_video_flutter_platform_interface.dart (1)

64-70: LGTM: Proper deprecation with clear migration guidance.

The deprecation annotation provides clear guidance about the replacement (StreamPictureInPictureAndroidView) and the error message correction from showPictureInPicture to setPictureInPictureEnabled improves accuracy.

packages/stream_video_flutter/android/src/main/kotlin/io/getstream/video/flutter/stream_video_flutter/MethodCallHandlerImpl.kt (1)

107-107: LGTM: Removal aligns with automatic PiP handling architecture.

The removal of manual PiP enable/disable method call handling is consistent with the refactoring to automatic PiP management via StreamFlutterActivity, simplifying the method channel implementation.

packages/stream_video_flutter/lib/stream_video_flutter_background.dart (1)

66-70: LGTM: Clean deprecation with backward compatibility.

The no-op implementation with detailed deprecation message provides a smooth migration path while maintaining backward compatibility. The approach is consistent with the platform interface deprecation.

packages/stream_video_flutter/lib/stream_video_flutter_method_channel.dart (1)

136-142: LGTM! Proper deprecation implementation.

The method is correctly deprecated with a clear message explaining the new approach. The no-op implementation maintains backward compatibility.

dogfooding/android/app/src/main/kotlin/io/getstream/video/flutter/dogfooding/MainActivity.kt (3)

12-19: Correct migration to StreamFlutterActivity.

The activity now properly extends StreamFlutterActivity which provides automatic PiP support, removing the need for manual PiP handling.


12-12: LGTM! Correct import for the new PiP implementation.

The import correctly references the new StreamFlutterActivity class from the Stream Video Flutter plugin.


19-19: Correct migration to StreamFlutterActivity for automatic PiP support.

This change properly implements the new PiP architecture by extending StreamFlutterActivity, which handles PiP lifecycle events automatically.

packages/stream_video_flutter/CHANGELOG.md (2)

3-9: Well-documented PiP improvements.

The changelog entry clearly describes the improvements, provides migration instructions, and notes backward compatibility.


3-9: LGTM! Comprehensive PiP improvement documentation.

The changelog entry clearly documents:

  • The new StreamFlutterActivity for automatic PiP support
  • Key improvements and fixes
  • Backwards compatibility information
  • Clear migration instructions
packages/stream_video_flutter/android/src/main/kotlin/io/getstream/video/flutter/stream_video_flutter/StreamFlutterActivity.kt (5)

8-19: Well-designed automatic PiP support.

The abstract class properly encapsulates PiP lifecycle management, making it easy for developers to adopt by simply extending this class.


21-26: LGTM! Proper PiP helper initialization.

The method correctly initializes the PictureInPictureHelper with the Flutter engine and provides the activity context via a lambda.


28-32: LGTM! Standard PiP trigger on user leave hint.

Correctly implements the Android pattern for entering PiP mode when the user presses the home button or switches apps.


42-49: LGTM! Proper PiP mode change notification.

Correctly notifies Flutter when the PiP mode state changes, allowing the Flutter side to update its UI accordingly.


34-40: Duplicate PiP triggers are no-ops

The handlePipTrigger implementation in
packages/stream_video_flutter/android/src/main/kotlin/io/getstream/video/flutter/stream_video_flutter/service/PictureInPictureHelper.kt
checks activity.isInPictureInPictureMode and returns immediately, preventing any redundant calls from both onUserLeaveHint() and onPause(). No changes required.

packages/stream_video_flutter/lib/src/call_screen/call_content/call_content.dart (2)

224-228: Correct integration of Android PiP widget.

The StreamPictureInPictureAndroidView is properly integrated into the widget tree, following the same pattern as the iOS implementation and respecting the PiP configuration settings.


224-228: LGTM! Consistent PiP widget integration for Android.

The Android PiP implementation now follows the same pattern as iOS, with a dedicated StreamPictureInPictureAndroidView widget integrated directly into the widget tree. This is cleaner than the previous lifecycle-based approach.

packages/stream_video_flutter/lib/src/call_screen/call_content/picture_in_picture/stream_picture_in_picture_android_view.dart (5)

38-47: Well-structured initialization logic.

The initialization properly checks the configuration before setting up listeners and correctly initializes all necessary components for PiP functionality.


49-72: Excellent widget update handling.

The method properly handles configuration changes and call updates with appropriate cleanup and re-initialization. This ensures the PiP state remains consistent with the widget configuration.


74-84: Proper resource cleanup in dispose.

The dispose method correctly cleans up all resources including listeners, overlays, and subscriptions, preventing memory leaks.


168-186: Comprehensive PiP eligibility checks.

The method properly validates all conditions including configuration settings, call status, and screen sharing state to determine if PiP should be allowed.


188-192: Appropriate build implementation.

Returning SizedBox.shrink() is correct since this widget manages PiP state without rendering visible content in the widget tree.

packages/stream_video_flutter/android/src/main/kotlin/io/getstream/video/flutter/stream_video_flutter/service/PictureInPictureHelper.kt (5)

16-42: Well-structured Flutter integration setup.

The initialization properly sets up the method channel communication with Flutter and handles the setPictureInPictureAllowed method correctly.


44-54: Proper PiP state management.

The method correctly updates the PiP allowed flag and handles disabling PiP mode when necessary with appropriate null safety checks.


68-81: Excellent PiP trigger handling with proper guards.

The method correctly avoids redundant PiP entries and properly notifies Flutter of mode changes. Good defensive programming by checking the current state first.


83-106: Comprehensive PiP mode entry with proper version handling.

The implementation correctly handles different Android versions, sets appropriate aspect ratios based on orientation, and utilizes Android 13+ seamless resize feature when available.


112-121: Excellent backward compatibility handling.

The deprecated method properly maintains backward compatibility while guiding users to the new API with clear deprecation messages.

Copy link

codecov bot commented Jul 1, 2025

Codecov Report

Attention: Patch coverage is 1.04167% with 95 lines in your changes missing coverage. Please review.

Project coverage is 4.16%. Comparing base (24cb87d) to head (492a436).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...icture/stream_picture_in_picture_android_view.dart 0.00% 82 Missing ⚠️
...ontent/picture_in_picture/android_pip_overlay.dart 0.00% 10 Missing ⚠️
...lib/src/call_screen/call_content/call_content.dart 25.00% 3 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##            main   #1003      +/-   ##
========================================
- Coverage   4.17%   4.16%   -0.01%     
========================================
  Files        571     573       +2     
  Lines      38459   38508      +49     
========================================
- Hits        1605    1604       -1     
- Misses     36854   36904      +50     

☔ 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: 3

🧹 Nitpick comments (1)
packages/stream_video_flutter/android/src/main/kotlin/io/getstream/video/flutter/stream_video_flutter/service/PictureInPictureHelper.kt (1)

7-7: Remove unused import.

The android.graphics.Rect import is not used anywhere in the code.

-import android.graphics.Rect
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e4a7455 and 1bf5648.

📒 Files selected for processing (1)
  • packages/stream_video_flutter/android/src/main/kotlin/io/getstream/video/flutter/stream_video_flutter/service/PictureInPictureHelper.kt (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: stream_video
  • GitHub Check: stream_video_push_notification
  • GitHub Check: analyze_legacy_version
  • GitHub Check: stream_video_flutter
  • GitHub Check: stream_video_noise_cancellation
  • GitHub Check: stream_video_screen_sharing
  • GitHub Check: build
  • GitHub Check: analyze
🔇 Additional comments (3)
packages/stream_video_flutter/android/src/main/kotlin/io/getstream/video/flutter/stream_video_flutter/service/PictureInPictureHelper.kt (3)

69-78: Excellent PiP trigger handling with redundancy check.

Good implementation that prevents redundant PiP entries and uses the new permission-based approach effectively.


84-107: Well-implemented PiP mode entry with proper version handling.

Excellent implementation that:

  • Includes proper Android version checks
  • Handles aspect ratio based on orientation
  • Uses modern PiP features like seamless resize when available
  • Provides fallback for older Android versions

The orientation-based aspect ratio calculation is particularly smart.


113-125: Exemplary deprecation handling with clear migration guidance.

This is an excellent example of how to deprecate APIs properly:

  • Clear deprecation annotation with specific alternative
  • Detailed error message with step-by-step migration instructions
  • Maintains backward compatibility while guiding developers to the new approach

This aligns perfectly with the PR objective of maintaining backward compatibility while encouraging migration.

Comment on lines +32 to +43
private fun handleMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) {
"setPictureInPictureAllowed" -> {
val isAllowed = call.arguments as Boolean
setPictureInPictureAllowed(isAllowed)
result.success(null)
}
else -> {
result.notImplemented()
}
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add type safety for method call arguments.

The type casting on line 35 could throw a ClassCastException if the Flutter side passes incorrect argument types.

         private fun handleMethodCall(call: MethodCall, result: MethodChannel.Result) {
             when (call.method) {
                 "setPictureInPictureAllowed" -> {
-                    val isAllowed = call.arguments as Boolean
-                    setPictureInPictureAllowed(isAllowed)
-                    result.success(null)
+                    try {
+                        val isAllowed = call.arguments as? Boolean
+                        if (isAllowed != null) {
+                            setPictureInPictureAllowed(isAllowed)
+                            result.success(null)
+                        } else {
+                            result.error("INVALID_ARGUMENT", "Expected Boolean argument", null)
+                        }
+                    } catch (e: Exception) {
+                        result.error("METHOD_CALL_ERROR", e.message, null)
+                    }
                 }
                 else -> {
                     result.notImplemented()
                 }
             }
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private fun handleMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) {
"setPictureInPictureAllowed" -> {
val isAllowed = call.arguments as Boolean
setPictureInPictureAllowed(isAllowed)
result.success(null)
}
else -> {
result.notImplemented()
}
}
}
private fun handleMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) {
"setPictureInPictureAllowed" -> {
try {
val isAllowed = call.arguments as? Boolean
if (isAllowed != null) {
setPictureInPictureAllowed(isAllowed)
result.success(null)
} else {
result.error("INVALID_ARGUMENT", "Expected Boolean argument", null)
}
} catch (e: Exception) {
result.error("METHOD_CALL_ERROR", e.message, null)
}
}
else -> {
result.notImplemented()
}
}
}
🤖 Prompt for AI Agents
In
packages/stream_video_flutter/android/src/main/kotlin/io/getstream/video/flutter/stream_video_flutter/service/PictureInPictureHelper.kt
between lines 32 and 43, the direct cast of call.arguments to Boolean can cause
a ClassCastException if the argument type is incorrect. To fix this, safely
check the type of call.arguments before casting, for example by using a
conditional cast or verifying the argument type, and handle the case where the
argument is not a Boolean by returning an error or defaulting safely.

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

🧹 Nitpick comments (2)
packages/stream_video_flutter/CHANGELOG.md (2)

5-5: Add the missing article in the “Automatic Activation” bullet
Minor grammar tweak for smoother reading.

-* **Automatic Activation:** PiP now triggers automatically when users press home button or background the app during calls.
+* **Automatic Activation:** PiP now triggers automatically when users press the Home button or background the app during calls.

7-7: Clarify phrasing in the “Migration Required” bullet
Makes the instruction more explicit and idiomatic.

-* **Migration Required:** In your `MainActivity`, remove the manual `onUserLeaveHint()` implementation and extend the MainActivity with `StreamFlutterActivity`. Previously required manually calling `PictureInPictureHelper.enterPictureInPictureIfInCall(this)` - now handled automatically.
+* **Migration Required:** In your `MainActivity`, remove the manual `onUserLeaveHint()` implementation and have your `MainActivity` extend `StreamFlutterActivity`. Previously, you had to call `PictureInPictureHelper.enterPictureInPictureIfInCall(this)` manually—this is now handled automatically.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 856ec9b and b6605dd.

📒 Files selected for processing (1)
  • packages/stream_video_flutter/CHANGELOG.md (1 hunks)
🧰 Additional context used
🪛 LanguageTool
packages/stream_video_flutter/CHANGELOG.md

[uncategorized] ~5-~5: You might be missing the article “the” here.
Context: ...triggers automatically when users press home button or background the app during cal...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)

⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: stream_video_noise_cancellation
  • GitHub Check: build
  • GitHub Check: stream_video_push_notification
  • GitHub Check: analyze
  • GitHub Check: stream_video_flutter
  • GitHub Check: stream_video

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: 1

♻️ Duplicate comments (2)
packages/stream_video_flutter/android/src/main/kotlin/io/getstream/video/flutter/stream_video_flutter/service/PictureInPictureHelper.kt (2)

18-22: Consider adding cleanup method for memory leak prevention.

The static references to methodChannel and getActivity could potentially cause memory leaks if not properly cleaned up when the Flutter engine is destroyed.

Consider adding a cleanup method:

+        fun cleanup() {
+            methodChannel?.setMethodCallHandler(null)
+            methodChannel = null
+            getActivity = null
+        }

32-43: Add type safety for method call arguments.

The type casting on line 35 could throw a ClassCastException if the Flutter side passes incorrect argument types.

         private fun handleMethodCall(call: MethodCall, result: MethodChannel.Result) {
             when (call.method) {
                 "setPictureInPictureAllowed" -> {
-                    val isAllowed = call.arguments as Boolean
-                    setPictureInPictureAllowed(isAllowed)
-                    result.success(null)
+                    try {
+                        val isAllowed = call.arguments as? Boolean
+                        if (isAllowed != null) {
+                            setPictureInPictureAllowed(isAllowed)
+                            result.success(null)
+                        } else {
+                            result.error("INVALID_ARGUMENT", "Expected Boolean argument", null)
+                        }
+                    } catch (e: Exception) {
+                        result.error("METHOD_CALL_ERROR", e.message, null)
+                    }
                 }
                 else -> {
                     result.notImplemented()
                 }
             }
         }
🧹 Nitpick comments (1)
packages/stream_video_flutter/CHANGELOG.md (1)

5-5: Fix minor grammatical issue.

Consider adding the missing article "the" for better readability.

-* **Automatic Activation:** PiP now triggers automatically when users press home button or background the app during calls.
+* **Automatic Activation:** PiP now triggers automatically when users press the home button or background the app during calls.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b6605dd and f71a02a.

📒 Files selected for processing (7)
  • packages/stream_video_flutter/CHANGELOG.md (1 hunks)
  • packages/stream_video_flutter/android/src/main/kotlin/io/getstream/video/flutter/stream_video_flutter/StreamFlutterFragmentActivity.kt (1 hunks)
  • packages/stream_video_flutter/android/src/main/kotlin/io/getstream/video/flutter/stream_video_flutter/service/PictureInPictureHelper.kt (2 hunks)
  • packages/stream_video_flutter/lib/src/call_screen/call_content/picture_in_picture/stream_picture_in_picture_android_view.dart (1 hunks)
  • packages/stream_video_flutter/lib/stream_video_flutter_background.dart (0 hunks)
  • packages/stream_video_flutter/lib/stream_video_flutter_method_channel.dart (0 hunks)
  • packages/stream_video_flutter/lib/stream_video_flutter_platform_interface.dart (0 hunks)
💤 Files with no reviewable changes (3)
  • packages/stream_video_flutter/lib/stream_video_flutter_platform_interface.dart
  • packages/stream_video_flutter/lib/stream_video_flutter_background.dart
  • packages/stream_video_flutter/lib/stream_video_flutter_method_channel.dart
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/stream_video_flutter/lib/src/call_screen/call_content/picture_in_picture/stream_picture_in_picture_android_view.dart
🧰 Additional context used
🪛 LanguageTool
packages/stream_video_flutter/CHANGELOG.md

[uncategorized] ~5-~5: You might be missing the article “the” here.
Context: ...triggers automatically when users press home button or background the app during cal...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)

⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: build
  • GitHub Check: stream_video_flutter
  • GitHub Check: stream_video_noise_cancellation
  • GitHub Check: stream_video_push_notification
  • GitHub Check: stream_video
  • GitHub Check: analyze
  • GitHub Check: analyze_legacy_version
🔇 Additional comments (11)
packages/stream_video_flutter/android/src/main/kotlin/io/getstream/video/flutter/stream_video_flutter/StreamFlutterFragmentActivity.kt (4)

8-18: LGTM! Well-documented base class design.

The class documentation clearly explains the purpose and provides a practical usage example. The abstract class design appropriately allows for extension while providing automatic PiP functionality.


28-32: LGTM! Proper PiP trigger on user leave.

The implementation correctly calls the parent method and triggers PiP when the user leaves the app (e.g., home button press).


34-40: Good defensive programming with isFinishing check.

The condition !isFinishing prevents PiP activation when the activity is being destroyed, which is the correct behavior.


42-49: LGTM! Proper PiP mode change notification.

The implementation correctly notifies Flutter about PiP mode state changes, enabling proper UI updates on the Flutter side.

packages/stream_video_flutter/android/src/main/kotlin/io/getstream/video/flutter/stream_video_flutter/service/PictureInPictureHelper.kt (6)

24-30: LGTM! Clean method channel initialization.

The method channel setup is well-structured and correctly initializes the communication bridge between Flutter and native Android.


45-55: LGTM! Proper PiP state management with automatic exit.

The implementation correctly manages the PiP allowed state and automatically exits PiP mode when disabled, ensuring consistent behavior.


69-78: Excellent defensive programming for PiP triggers.

The redundancy check prevents unnecessary PiP calls and the condition gating ensures PiP only activates when appropriate. This is a significant improvement over the previous implementation.


80-84: LGTM! Proper main thread enforcement addressed.

The implementation correctly ensures method channel calls are made on the main thread using runOnUiThread, addressing the previous review concern.


86-109: Well-implemented PiP mode entry with proper aspect ratio handling.

The implementation correctly:

  • Checks capabilities before attempting PiP entry
  • Sets appropriate aspect ratios based on orientation
  • Enables seamless resize on supported Android versions
  • Provides fallback for older Android versions

111-113: LGTM! Simple and effective capability check.

The method correctly verifies device PiP support before attempting to enter PiP mode.

packages/stream_video_flutter/CHANGELOG.md (1)

3-9: Comprehensive documentation of breaking changes.

The changelog clearly explains the PiP improvements, migration requirements, and removed deprecated methods. This provides excellent guidance for developers upgrading to the new implementation.

@Brazol Brazol merged commit f6e0f47 into main Jul 2, 2025
11 of 13 checks passed
@Brazol Brazol deleted the chore/android-pip-improvements branch July 2, 2025 13:35
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.

2 participants