Skip to content

Conversation

@Zeronfinity
Copy link
Collaborator

@Zeronfinity Zeronfinity commented Dec 5, 2025

Description

This PR adopts the new CameraX Feature Group API to validate feature combinations and dynamically update system constraints. This ensures that the app only allows supported combinations of settings (e.g., HDR, FPS, Stabilization), preventing runtime failures on devices that do not support specific combinations (like HDR + 60 FPS on Pixel 9).

Key Changes

  • CameraX Update: Updated CameraX dependencies to 1.6.0-SNAPSHOT to access the stable Feature Groups API.
  • Feature Mapping: Added FeatureGroupData to map JCA internal models (DynamicRange, VideoQuality, StabilizationMode, etc.) to CameraX's GroupableFeature.
  • Dynamic Constraints: Implemented updateSystemConstraintsByFeatureGroups in CameraXCameraSystem. This method asynchronously validates the current session settings against the device capabilities and filters out unsupported options for other settings (e.g., if 60 FPS is selected, it might disable HDR if they can't be used together).
  • Refactoring: Migrated from UseCaseGroup to SessionConfig for single camera session creation to align with the new API usage and allow for isSessionConfigSupported checks.

Bug Fixes & Enhancements

  • Fixes a crash/black screen issue on Pixel 9 devices when enabling both HDR and 60 FPS.
  • Stream mode is now selectable based on whether supported, rather being always disabled, when HDR is enabled.
  • Feature combinations can now be supported more often (due to the additional guaranteed combinations from feature combination query API), e.g. UHD recording with single stream mode in Samsung S23U.

Known Limitations & Future Work

System constraints not updating for multiple updates from setting screen

The system constraints are currently updated only when the camera session is initialized or re-created (e.g., upon returning to the preview screen). This means that if a user sets feature options (like UHD and 60 FPS) directly from the settings menu without navigating back to the preview screen, the system constraints is not re-evaluated.
Consequently, it allows users to select a combination of features that are not mutually supported by the device, which can lead to issues when they eventually navigate back to the preview screen.

TODO: Addressing this limitation requires further architectural refactoring to trigger constraint updates dynamically upon any individual setting change. Or, the constraints repository should be updated with the info of all possible constraints at initialization, rather than only the settings state navigable from the current settings state.

Features incompatible with CameraX Feature Group API

CameraX depends on the Camera2 feature combination query (FCQ) API which guarantees support only a limited set of features. So, the scenarios using features incompatible with the FCQ API do not get much benefits from this PR.

Asynchronous system constraints update

System constraints are updated asynchronously, creating a window where a user might enable an unsupported combination of features before the update completes.

Future Work: This could be addressed by waiting for the constraints update to finish and restricting setting changes until it is complete.

Tests

  • Added FeatureGroupDataTest (unit tests) to verify mapping logic between JCA models and CameraX GroupableFeature.
  • Added setMultipleFeatures_systemConstraintsUpdatedAndFeaturesSetIfSupported to CameraXCameraSystemTest (integration test) to verify that the camera system dynamically updates constraints and sets features correctly based on CameraX feature group compatibility.

Additional Context

Related Issues

@Zeronfinity Zeronfinity requested a review from temcguir December 5, 2025 18:50
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @Zeronfinity, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the camera's robustness by integrating the new CameraX Feature Combination Query API. The primary goal is to prevent application crashes and ensure a smoother user experience by dynamically checking and enforcing device compatibility for various camera settings. By mapping internal camera features to CameraX's GroupableFeature and refactoring session management, the system can now intelligently adapt to device limitations, particularly resolving issues with incompatible settings like HDR and high frame rates.

Highlights

  • CameraX API Update: The project has updated its CameraX dependencies to 1.6.0-SNAPSHOT to leverage the new Feature Combination Query API, which allows for dynamic validation of camera setting combinations.
  • Dynamic System Constraints: A new mechanism, updateSystemConstraintsByFeatureGroups, has been implemented to asynchronously validate current session settings against device capabilities. This filters out unsupported options for various camera settings (e.g., HDR, FPS, Stabilization), preventing runtime failures.
  • Feature Mapping: A new FeatureGroupData structure has been introduced to map internal JCA camera models (like DynamicRange, VideoQuality, StabilizationMode) to CameraX's GroupableFeature objects, enabling the new API's functionality.
  • Session Configuration Refactoring: The camera session creation process has been refactored to migrate from UseCaseGroup to SessionConfig, aligning with the new CameraX API usage and facilitating isSessionConfigSupported checks for feature compatibility.
  • Bug Fix: This change specifically addresses and fixes a crash/black screen issue observed on Pixel 9 devices when both HDR and 60 FPS were enabled simultaneously, by dynamically disabling conflicting features.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@Zeronfinity
Copy link
Collaborator Author

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request is an excellent and significant update that adopts the new CameraX Feature Group API. The migration from UseCaseGroup to SessionConfig for single camera sessions, along with the dynamic validation of feature combinations, is well-executed and crucial for preventing runtime failures on various devices. The introduction of FeatureGroupData provides a clean mapping layer, and the asynchronous updating of system constraints is a thoughtful performance consideration. My feedback is focused on improving test coverage for the complex new logic and ensuring adherence to the project's testing style guide.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request successfully adopts the new CameraX Feature Combination Query API, which is a significant and valuable improvement for ensuring device compatibility and preventing runtime errors with unsupported feature combinations. The refactoring from UseCaseGroup to SessionConfig for single camera sessions is well-executed and aligns with modern CameraX practices. The introduction of FeatureGroupData and the dynamic constraint filtering in CameraXCameraSystem are the core of this change and are logically sound.

My review includes a few critical and high-severity findings. One critical issue is a compilation error in the new filtering logic due to using a suspend function within a non-suspend lambda. Another high-severity issue relates to potential resource leaks from improper CoroutineScope creation within a frequently called helper function. I've also included suggestions for improving code structure and adhering to the project's testing style guide. Addressing these points will enhance the robustness and maintainability of this new implementation.

@Zeronfinity Zeronfinity force-pushed the tahsinm/cxfg-adoption branch 2 times, most recently from 43a556c to 70fa0fa Compare December 6, 2025 08:17
@Zeronfinity
Copy link
Collaborator Author

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request is a significant and well-executed refactoring to adopt the new CameraX Feature Combination Query API. The changes are extensive, touching on session creation, constraint management, and settings application, but they are well-structured and improve the overall architecture. The migration from UseCaseGroup to SessionConfig for single camera sessions is a great modernization. The introduction of FeatureGroupData and the associated logic to dynamically filter system constraints is a robust solution to prevent crashes from unsupported feature combinations.

I've identified one high-severity issue regarding side effects in a feature-checking function that should be addressed. I've also included a suggestion to enhance the new integration test to make it more robust. Overall, this is excellent work.

@Zeronfinity Zeronfinity force-pushed the tahsinm/cxfg-adoption branch from f56b76a to bde634e Compare December 8, 2025 12:47
@Zeronfinity
Copy link
Collaborator Author

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request successfully adopts the new CameraX Feature Group API, which is a significant and complex undertaking. The refactoring from UseCaseGroup to SessionConfig is well-executed, and the new logic for dynamically updating system constraints based on feature combinations is robust. I particularly appreciate the addition of comprehensive unit and integration tests, which ensure the new functionality is reliable. The fix to call setSurfaceProvider on the main thread is also a crucial correction. I have one suggestion to improve the efficiency of the feature support checks.

@Zeronfinity
Copy link
Collaborator Author

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request successfully adopts the new CameraX Feature Group API, which is a significant and valuable improvement. The changes allow for dynamic validation of feature combinations, preventing runtime crashes on devices with unsupported settings like HDR + 60 FPS. The refactoring from UseCaseGroup to SessionConfig for single camera sessions is well-executed and aligns with modern CameraX practices. The introduction of FeatureGroupData and the related mapping logic is clear and well-tested. The new integration test (setMultipleFeatures_systemConstraintsUpdatedAndFeaturesSetIfSupported) is particularly strong, as it verifies the dynamic constraint updates across various feature permutations. I have a couple of minor suggestions to improve code style and ensure documentation stays in sync with build changes. Overall, this is an excellent contribution that enhances the app's stability and correctness.

@Zeronfinity Zeronfinity marked this pull request as ready for review December 8, 2025 14:02
@Zeronfinity Zeronfinity force-pushed the tahsinm/cxfg-adoption branch from b8feb82 to c577a74 Compare December 8, 2025 18:57
Comment on lines +721 to +753
captureMode: CaptureMode,
backgroundDispatcher: CoroutineDispatcher,
targetFrameRate: Int? = null,
stabilizationMode: StabilizationMode? = null,
dynamicRange: DynamicRange? = null,
videoQuality: VideoQuality? = null
): VideoCapture<Recorder>? {
if (captureMode != CaptureMode.STANDARD && captureMode != CaptureMode.VIDEO_ONLY) {
return null
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I suggest removing captureMode from this function and returning a non-nullable VideoCapture<Recorder>. The captureMode check should happen at the call site (similar to createImageUseCase) to avoid unnecessary argument passing and implicit null returns.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I am fine with changing it back to that, but note that there are multiple call sites for this and the captureMode checking logic is duplicate in all of those places then (3 places in total with this PR). I had moved captureMode inside the function mainly to avoid this duplicate checking in all 3 places. WDYT?

Comment on lines +813 to +839
withContext(Dispatchers.Main) {
setSurfaceProvider { surfaceRequest ->
surfaceRequests.update { surfaceRequest }
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm assuming this withContext was added so that this can be called from within the featuregroup check? Do we need to set a surface provider just to check for capabilities?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Short answer: not really.

As explained below, I implemented it this way for a few reasons. Regardless, this should be a JCA decision and I am happy to change this to however you prefer (or at least leave some TODO comments for later in case we decide to do something a bit more complicated).

  1. I was trying to avoid different code flows for capability query and actual binding as much as possible.

Needing too many different code flow paths often leads to code smell and we've had developers complaining about similar situation recently as well. So, I tried to keep functions like createPreviewUseCase as generic as possible without having different code flows in these functions based on whether the intention is capability query or binding.

  1. In future, we may use the user-provided surface in query directly (only if users have already provided the surface).

In some cases, the framework-layer FCQ API wants to have concrete surfaces, not deferred ones. Right now, CameraX creates such surfaces for queries, even when surface provider is already providing one. However, this may lead to different results in query and binding (in rare cases though), and there's also an optimization opportunity here. So, we may end up using the user-provided surface in future (only if already provided, it won't be a hard requirement). But this is kinda moot point for this PR since we are using defaultCameraSessionContext during query here which probably doesn't set up the surfaceRequests flow correctly anyway.

Comment on lines 851 to 857
createSessionConfig(
cameraConstraints = cameraConstraints,
initialTransientSettings = transientSettings,
videoCaptureUseCase = videoCaptureUseCase,
sessionSettings = sessionSettings,
sessionScope = CoroutineScope(defaultDispatcher + job)
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

This seems quite expensive. Any time we want to call supportsGrouping, which happens when we change a setting, we set up and creating an entire pipeline (including use cases, effects, etc.). Maybe it's unavoidable, but do we really need to do this every time we change settings? Are there enough combinations of settings that we couldn't just do this once up front during initialization? Maybe there is, but I would much prefer exploring that approach if it meant we could avoid this type of check whenever we change a setting.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That is a valid concern regarding the overhead. The CameraX isSessionConfigSupported API for querying feature groups require a full SessionConfig because support can be influenced by session-wide variables like CameraEffect, use case resolutions, aspect ratios etc.

To ensure accuracy without assuming which scenarios might conflict in the JCA codebase (specially since I am not too well-versed with all scenarios in JCA and future plans), I have followed the framework's contract strictly for now. I agree that pre-calculation can be a great optimization since the number of factors that can change the result may not be too high for JCA, so I've added a TODO (in FeatureGroupHandler.isGroupingSupported) suggesting a persistence-based approach for the team to explore in future.

Does that work for this PR?

@Zeronfinity Zeronfinity force-pushed the tahsinm/cxfg-adoption branch from c577a74 to 99b56bd Compare January 12, 2026 19:55
@Zeronfinity Zeronfinity force-pushed the tahsinm/cxfg-adoption branch from 99b56bd to e8a4f78 Compare January 12, 2026 20:14
@Zeronfinity Zeronfinity force-pushed the tahsinm/cxfg-adoption branch from e8a4f78 to abaabeb Compare January 12, 2026 20:52
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.

Adopt CameraX Feature Groups API in JCA Camera session failure with HDR + 60 FPS

2 participants