Skip to content

[net11] [Android] Implemented material3 support for CarouselView - #35640

Draft
Dhivya-SF4094 wants to merge 12 commits into
dotnet:mainfrom
Dhivya-SF4094:material3_Carousel
Draft

Dhivya-SF4094 wants to merge 12 commits into
dotnet:mainfrom
Dhivya-SF4094:material3_Carousel

Conversation

@Dhivya-SF4094

@Dhivya-SF4094 Dhivya-SF4094 commented May 27, 2026 •

Copy link
Copy Markdown
Contributor

Description of Change

This pull request introduces a new implementation for Material Design Carousel support in the Android handler code, focusing on compatibility with Material's CarouselLayoutManager and its unique requirements. The most significant changes include the addition of new adapter and view holder classes that wrap carousel items in a MaskableFrameLayout, a new scroll listener tailored for Material's carousel, and several extensibility points in the base classes to support these requirements. There are also targeted refactors to enable more flexible handling of looping and empty views.

Material Carousel Support and Adapter Enhancements:

  • Added CarouselViewAdapter2, a new adapter for MauiCarouselRecyclerView2, which wraps each item in a MaskableFrameLayout to satisfy Material's CarouselLayoutManager requirements. This adapter also disables virtual looping, exposing the real item count to avoid performance issues and infinite layout loops with the Material carousel. (src/Controls/src/Core/Handlers/Items2/Android/Adapters/CarouselViewAdapter2.cs)
  • Introduced MaskableCarouselItemViewHolder, a view holder that manages MAUI content inside a MaskableFrameLayout, ensuring the correct handling of item templates and data binding for the Material carousel. (src/Controls/src/Core/Handlers/Items2/Android/MaskableCarouselItemViewHolder.cs)
  • Added CarouselViewOnScrollListener2, a scroll listener tailored for MauiCarouselRecyclerView2 that works directly with CarouselLayoutManager and does not depend on the legacy loop manager. It accurately tracks visible items and snap positions.(src/Controls/src/Core/Handlers/Items2/Android/CarouselViewOnScrollListener2.cs)
  • Raw string items (a CarouselView bound to plain strings with no ItemTemplate) are also wrapped in a MaskableFrameLayout via MaskableTextItemViewHolder, since CarouselLayoutManager rejects any direct RecyclerView child that is not a MaskableFrameLayout.
  • The Material handler renders the EmptyView using a plain LinearLayoutManager instead of Material's CarouselLayoutManager. MauiCarouselRecyclerView2.SelectLayoutManager returns a LinearLayoutManager whenever the active adapter is the EmptyViewAdapter, because Material's keyline mask (sized for full-viewport carousel items) would collapse a normally-sized EmptyView.

Loop Logic Improvements:

  • Refactored loop logic in MauiCarouselRecyclerView by introducing the IsLoopEnabled property, allowing subclasses to override loop behavior (for example, to disable looping when using a layout manager that does not support virtual looping), and replaced direct checks of Carousel.Loop with IsLoopEnabled throughout the code.

Important

The Material3 path is locked to FullScreenCarouselStrategy (one item masked to the full viewport, snapping one page at a time). The following CarouselView behaviors are intentionally not supported under this strategy and are documented in code:

  • Loop is not supported. Material's CarouselLayoutManager has no virtual-range model, so the legacy LoopScale (≈16384) trick used by the LinearLayoutManager path causes infinite measure/GC loops. Handler2 forces non-loop behavior (IsLoopEnabled => false) and exposes the real item count. Keep CarouselView.Loop="False".
  • PeekAreaInsets is not supported. FullScreenCarouselStrategy masks every item to fill the viewport, so there is no peek of adjacent items. The mapper is a documented no-op and item sizing deliberately ignores the insets.
  • LinearItemsLayout.ItemSpacing is not honoured. Material's CarouselLayoutManager has no spacing API, and it builds its KeylineState from the decorated measured size of the first child — so injecting spacing offsets (decoration/margins) would distort the keyline geometry. With full-viewport single-snap pages there is also no inter-item gutter for spacing to occupy. It is a documented no-op.
  • Per-item visual states are not surfaced. CurrentItem/PreviousItem/NextItem/DefaultItem are only observable when adjacent items peek into view (the docs example uses PeekAreaInsets="100"). Because Handler2 has no peek and shows only the current item at a time, these states are not driven. This is documented as an explicit limitation to revisit if a non-full-screen strategy with peek support is added.

Each limitation is scoped to FullScreenCarouselStrategy and can be revisited if strategy-aware sizing (MultiBrowse/Hero/Uncontained) is wired up via CreateCarouselStrategy.

Fixed

Fixes #35637

Screenshots

Before  After
 
35637_BeforeChanges.mov
  
35637_AfterChanges.mov

UI Test results

Material2  Material3 
      

@github-actions

github-actions Bot commented May 27, 2026 •

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 35640

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 35640"

@dotnet-policy-service dotnet-policy-service Bot added the partner/syncfusion Issues / PR's with Syncfusion collaboration label May 27, 2026
@github-actions github-actions Bot added area-controls-collectionview CollectionView, CarouselView, IndicatorView platform/android labels May 27, 2026
@kubaflo

kubaflo commented May 27, 2026

Copy link
Copy Markdown
Contributor

/review -b feature/refactor-copilot-yml

1 similar comment
@kubaflo

kubaflo commented May 28, 2026

Copy link
Copy Markdown
Contributor

/review -b feature/refactor-copilot-yml

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Expert Review — 6 findings

See inline comments for details.

@MauiBot MauiBot added s/agent-fix-win AI found a better alternative fix than the PR s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels May 28, 2026
@MauiBot

This comment has been minimized.

@kubaflo kubaflo 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.

Could you check the ai's suggestions?

@Dhivya-SF4094
Dhivya-SF4094 force-pushed the material3_Carousel branch 2 times, most recently from 4b948d7 to 90d2165 Compare June 4, 2026 12:13
@kubaflo

kubaflo commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

/review -b feature/enhanced-reviewer -p android

@MauiBot

This comment has been minimized.

@kubaflo

kubaflo commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

/review rerun

@github-actions github-actions Bot added the s/agent-ready-for-rerun AI review has a new PR-author comment or commit and is ready for rerun label Jun 10, 2026
@kubaflo

kubaflo commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

/review -b feature/enhanced-reviewer -p android

@github-actions github-actions Bot added s/agent-review-in-progress AI review is currently running for this PR and removed s/agent-ready-for-rerun AI review has a new PR-author comment or commit and is ready for rerun labels Jun 10, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Expert Review — 6 findings

See inline comments for details.

MauiBot

This comment was marked as outdated.

@kubaflo

kubaflo commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

/review -b feature/enhanced-reviewer -p android

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Jun 11, 2026
MauiBot

This comment was marked as outdated.

@MauiBot MauiBot removed the s/agent-review-in-progress AI review is currently running for this PR label Jun 11, 2026
@sheiksyedm

sheiksyedm commented Aug 6, 2026 •

Copy link
Copy Markdown
Contributor

Can we merge it?

@kubaflo We can hold this for now. We need to discuss the Material Carousel behavior further, as the new Material implementation will not support some existing MAUI APIs that users may expect to work.

Please hold off on merging this PR until we confirm the behavior.

@kubaflo

This comment has been minimized.

@MauiBot

This comment has been minimized.

@kubaflo kubaflo 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.

Could you please resolve the merge conflicts?

@kubaflo

This comment has been minimized.

@MauiBot

This comment has been minimized.

@kubaflo

kubaflo commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

could you please resolve conflicts

@Dhivya-SF4094

Copy link
Copy Markdown
Contributor Author

Resolved conflicts in this PR, Please review once.

@kubaflo

This comment has been minimized.

@github-actions

Copy link
Copy Markdown
Contributor

Note

🔍 /review started

AzDO build 15379505 is running for android.

The s/agent-review-in-progress label stays on this PR while the run is active. The final recommendation and outcome labels are posted only after Gate, expert review, and Deep UI tests finish.

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Expert Review — 1 findings

See inline comments for details.

// Subclasses backed by a layout manager that has no virtual-range concept
// (e.g. Material's CarouselLayoutManager) can override this to force the
// non-loop code paths regardless of the public Carousel.Loop value.
protected virtual bool IsLoopEnabled => Carousel?.Loop == true;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🔍 AI-Generated Review (multi-model)

[major] Logic and Correctness — The new IsLoopEnabled abstraction is only partially applied: later collection-change paths in this same type still branch on Carousel.Loop directly (for example CollectionItemsSourceChanged/HandleReplaceAction). In the Material3 subclass (MauiCarouselRecyclerView2) where IsLoopEnabled is forced false, a Loop=true CarouselView can still enter loop-only recentering on collection mutations and jump to virtual-range indexes against a non-loop adapter, producing incorrect post-update position/current-item behavior.

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

AI Review Summary

@Dhivya-SF4094 — new AI review results are available based on commit e7e479a.

Gate Inconclusive Confidence Medium Platform Android


🗂️ Review Sessions — click to expand
🚦 Gate — Test Before & After Fix

Gate Result: ⚠️ INCONCLUSIVE

Platform: ANDROID · Base: net11.0 · Merge base: d73fb56e

🩺 Pre-existing build failure (not the fix) — both the without-fix baseline AND the with-fix build fail with a build error, so the PR's fix is NOT the cause. This is a broken main/merge-base or a toolchain/environment failure (e.g. an ILLink IL1012 trimmer crash). The gate cannot verify anything; investigate the build environment rather than the PR.

/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/37.2.0-rc.2.56/tools/Xamarin.Android.Tooling.targets(55,5): error XARSD7028: System.IO.FileNotFoundException: Could not load file or assem...

Test Without Fix (expect FAIL) With Fix (expect PASS)
🖥️ Material3CarouselViewFeatureTests Material3CarouselViewFeatureTests 🛠️ BUILD ERROR 🛠️ BUILD ERROR
🔴 Without fix — 🖥️ Material3CarouselViewFeatureTests: 🛠️ BUILD ERROR · 166s

Error-relevant lines (filtered from the build log):

/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/37.2.0-rc.2.56/tools/Xamarin.Android.Tooling.targets(55,5): error XARSD7028: System.IO.FileNotFoundException: Could not load file or assembly 'System.Diagnostics.TraceSource, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified. [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net11.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/37.2.0-rc.2.56/tools/Xamarin.Android.Tooling.targets(55,5): error XARSD7028:  [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net11.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/37.2.0-rc.2.56/tools/Xamarin.Android.Tooling.targets(55,5): error XARSD7028: File name: 'System.Diagnostics.TraceSource, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net11.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/37.2.0-rc.2.56/tools/Xamarin.Android.Tooling.targets(55,5): error XARSD7028: Requested by: netstandard, Version=2.1.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51 [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net11.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/37.2.0-rc.2.56/tools/Xamarin.Android.Tooling.targets(55,5): error XARSD7028:  --> Microsoft.Deployment.DotNet.Releases, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net11.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/37.2.0-rc.2.56/tools/Xamarin.Android.Tooling.targets(55,5): error XARSD7028:  --> System.Private.CoreLib, Version=11.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net11.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/37.2.0-rc.2.56/tools/Xamarin.Android.Tooling.targets(55,5): error XARSD7028:    at Xamarin.Android.Tasks.ResolveSdks.RunTask() [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net11.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/37.2.0-rc.2.56/tools/Xamarin.Android.Tooling.targets(55,5): error XARSD7028:    at Microsoft.Android.Build.Tasks.AndroidTask.Execute() [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net11.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/37.2.0-rc.2.56/tools/Xamarin.Android.Tooling.targets(55,5): error XARSD7028: [cached failure] Failed to open file '/home/vsts/work/1/s/.dotnet/shared/Microsoft.NETCore.App/11.0.0-rc.2.26467.104/System.Diagnostics.TraceSource.dll'. The system cannot find the file specified. [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net11.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/37.2.0-rc.2.56/tools/Xamarin.Android.Tooling.targets(55,5): error XARSD7028:  (0x80070002) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net11.0-android]
Build FAILED.
🟢 With fix — 🖥️ Material3CarouselViewFeatureTests: 🛠️ BUILD ERROR · 145s

Error-relevant lines (filtered from the build log):

/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/37.2.0-rc.2.56/tools/Xamarin.Android.Tooling.targets(55,5): error XARSD7028: System.IO.FileNotFoundException: Could not load file or assembly 'System.Diagnostics.TraceSource, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified. [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net11.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/37.2.0-rc.2.56/tools/Xamarin.Android.Tooling.targets(55,5): error XARSD7028:  [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net11.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/37.2.0-rc.2.56/tools/Xamarin.Android.Tooling.targets(55,5): error XARSD7028: File name: 'System.Diagnostics.TraceSource, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net11.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/37.2.0-rc.2.56/tools/Xamarin.Android.Tooling.targets(55,5): error XARSD7028: Requested by: netstandard, Version=2.1.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51 [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net11.0-android]

This Gate section was shortened to keep every required review section visible. Full details remain available in the pipeline build artifacts.


📋 Pre-Flight — Context & Validation

Issue: #35637 - [Android] Implement material3 support for CarouselView
PR: #35640 - [net11] [Android] Implemented material3 support for CarouselView
Platforms Affected: Android (net11.0, Material 3 path)
Files Changed: 10 implementation/API files, 1 UI test file, 1 repository-instruction file (1,383 additions, 74 deletions)

Key Findings

  • The PR conditionally registers Items2.CarouselViewHandler2 for Android when RuntimeFeature.IsMaterial3Enabled is true. The new handler uses Material's CarouselLayoutManager with FullScreenCarouselStrategy.
  • Direct recycler children are wrapped in MaskableFrameLayout; custom templated/text holders, an adapter, and a Material-specific scroll listener provide binding, sizing, snapping, position, and empty-view behavior.
  • The PR avoids feeding the legacy approximately 16,384-item virtual loop range to CarouselLayoutManager by exposing the real item count and forcing non-loop code paths. It explicitly leaves Loop, PeekAreaInsets, LinearItemsLayout.ItemSpacing, and per-item visual states unsupported on this path.
  • The linked issue asks broadly for Material 3 presentation and interaction while retaining consistency with MAUI. A maintainer asked that merge be held while unsupported existing CarouselView APIs were discussed.
  • A prior August review tried bounded edge-jump wrapping with the real item count and reported the focused CarouselView regression scope passing. New candidates must not repeat either that edge-jump mechanism or the PR's force-non-loop mechanism.
  • The current gate is INCONCLUSIVE, not failing: both baseline and PR builds stop in the Android SDK before tests because System.Diagnostics.TraceSource.dll is missing. The PR remains unverified by this run.
  • The mechanical regression cross-reference is clean. Detected UI categories are CollectionView and Material3.
  • The PR includes six new production files. try-fix must honor EstablishBrokenBaseline.ps1; if its baseline state reports any NewFiles, the attempt must be recorded as Blocked without editing rather than bypassing restoration safeguards.

Code Review Summary

Verdict: SKIPPED
Confidence: N/A
Errors: 0 | Warnings: 0 | Suggestions: 0

Key code review findings:

  • Dedicated expert review is intentionally reserved for STEP 5b; STEP 5a gathered context and inspected the diff only.

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #35640 Register a Material-specific Items2 handler, wrap all item roots in MaskableFrameLayout, use CarouselLayoutManager, and disable unsupported looping by exposing the real item count. ⚠️ INCONCLUSIVE (Gate) 10 implementation/API files Build environment failed before the focused Android UI tests could run.

Primary test command: pwsh .github/scripts/BuildAndRunHostApp.ps1 -Platform android -TestFilter "Material3CarouselViewFeatureTests"

Additional mandatory regression tests: None were supplied for STEP 5a; do not run category-wide or full suites.


🔬 Code Review — Deep Analysis

Expert Evaluation — Raw PR

Verdict: NEEDS_CHANGES
Confidence: medium

Independent Assessment

The submitted Android Material 3 path registers Items2.CarouselViewHandler2, wraps every direct recycler child in a Material MaskableFrameLayout, uses CarouselLayoutManager with FullScreenCarouselStrategy, and exposes the real source count instead of MAUI's approximately 16,384-position virtual loop range. The approach addresses the reported Material layout/GC failure, but intentionally does not implement Loop, PeekAreaInsets, LinearItemsLayout.ItemSpacing, or per-item visual states.

Blocking Finding

  • [major] Logic and Correctness — loop abstraction is applied inconsistently. MauiCarouselRecyclerView2.IsLoopEnabled returns false, but collection-change branches inherited from MauiCarouselRecyclerView still inspect Carousel.Loop directly. Because CarouselView.Loop defaults to true, an add/remove/replace can enter virtual-loop recentering or loop-specific rebind behavior while CarouselViewAdapter2 exposes only the real item count. The resulting virtual target/index assumptions are incompatible with the Material adapter and can leave Position/CurrentItem or the displayed item incorrect after a mutation. The expert finding is anchored at src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs:127.

Test and Review Evidence

  • The trusted Gate is INCONCLUSIVE, not failed: both baseline and PR builds stopped before test execution because the Android SDK could not load System.Diagnostics.TraceSource.dll.
  • The regression cross-reference is CLEAN with no overlap or revert findings.
  • The change is platform-specific handler/UI plumbing in the frequently regressed CarouselView family, so confidence is capped at medium by blast radius and further reduced by the unexecuted focused Android tests.
  • Live required-check and prior-review queries were unavailable through unauthenticated gh; this does not change the code-level finding.

Required Refinement

Apply the IsLoopEnabled abstraction consistently to every inherited path whose behavior assumes the virtual loop adapter, then run the single required focused command in the authorized pr-plus-reviewer sandbox. No broader redesign or full-suite validation is warranted in this pass.


🛠️ Try-Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 gpt-5.3-codex try-fix Use the Material handler only for non-looping carousels; retain the legacy Android handler for Loop=true. ⚠️ BLOCKED 0 files Harness-owned dirty worktree prevented baseline establishment; no edit or test was permitted.
2 gpt-5.6-sol try-fix Keep Material active and implement looping through a rotating three-slot logical adapter window. ⚠️ BLOCKED 0 files The same baseline-safety block prevented implementation and testing.
PR PR #35640 Register a Material-specific Items2 handler, use CarouselLayoutManager with maskable item roots, expose the real item count, and force non-loop behavior. ⚠️ INCONCLUSIVE (Gate) 10 implementation/API files Both baseline and PR builds failed in the Android SDK because System.Diagnostics.TraceSource.dll was missing.

Candidate 1 Narrative

Candidate 1 avoids both the PR's force-non-loop behavior and the previously tried edge-jump mechanism. It keeps the approximately 16,384-item legacy virtual range away from Material's layout manager by selecting the existing legacy handler for looped carousels and reserving Material's handler for explicitly non-looping instances. The approach could not be implemented because EstablishBrokenBaseline.ps1 rejected the pre-existing harness changes before creating a baseline. It therefore remains unverified rather than failed.

Candidate 2 Narrative

Candidate 2 also avoids every earlier mechanism. It retains the Material handler for both loop modes but gives CarouselLayoutManager only three physical slots. A logical anchor maps those slots to previous/current/next source items and rotates after each settled page, keeping the landed item centered without a real-list edge jump. This is more behaviorally complete than disabling loop but materially more complex: source counts below three, mutations, directionality, gesture settling, and programmatic position synchronization all need focused validation. Baseline establishment failed before any edit or test, so this candidate is also unverified rather than failed.

Comparison

Candidate Main Advantage Main Risk
1 Reuses mature legacy loop behavior and keeps Material's layout manager isolated from virtual looping. Default Loop=true would not use the Material carousel, and per-instance selection must occur inside a hybrid handler because DI handler registration is global.
2 Keeps the Material carousel active while bounding its physical adapter range and preserving conceptual loop semantics. Introduces non-trivial logical/physical position mapping and collection-update edge cases.

Cross-Pollination

Skipped by the STEP 5a hard execution contract.

Exhausted: Yes — the hard two-candidate budget was consumed; no follow-up or audit agents were launched.

Selected Fix: None — selection is limited to passing candidates, and both alternatives were blocked before implementation/testing while the PR gate was inconclusive. Candidate 1 is simpler; candidate 2 preserves more Material behavior, but neither has empirical evidence from this run.


📝 PR Finalize — Recommended Title & Description

Assessment: ✏️ Recommend updating — the current description incorrectly says all direct Carousel.Loop checks were replaced, while the submitted HEAD retains virtual-loop branches in collection and loop-update paths.

Recommended title

[net11] [Android] CarouselView: Add Material 3 CarouselLayoutManager support

Recommended description

### Description of Change

This pull request introduces a Material Design Carousel implementation in the Android handler code, focused on compatibility with Material's `CarouselLayoutManager` and its unique requirements. It adds adapter and view-holder classes that wrap carousel items in a `MaskableFrameLayout`, a Material-specific scroll listener, and extensibility points in the existing carousel base classes. It also includes targeted changes for loop-sensitive paths and EmptyView layout.

**Material Carousel Support and Adapter Enhancements:**

* Added `CarouselViewAdapter2`, a new adapter for `MauiCarouselRecyclerView2`, which wraps each item in a `MaskableFrameLayout` to satisfy Material's `CarouselLayoutManager` requirements. This adapter disables virtual looping and exposes the real item count to avoid the performance problems and infinite layout loops caused by giving Material's carousel the legacy virtual range. (`src/Controls/src/Core/Handlers/Items2/Android/Adapters/CarouselViewAdapter2.cs`)
* Introduced `MaskableCarouselItemViewHolder`, which manages MAUI content inside a `MaskableFrameLayout` and handles item templates and data binding for the Material carousel. (`src/Controls/src/Core/Handlers/Items2/Android/MaskableCarouselItemViewHolder.cs`)
* Added `CarouselViewOnScrollListener2`, which works directly with `CarouselLayoutManager`, does not depend on the legacy loop manager, and tracks visible items and snap positions. (`src/Controls/src/Core/Handlers/Items2/Android/CarouselViewOnScrollListener2.cs`)
* Raw string items (a `CarouselView` bound to plain strings with no `ItemTemplate`) are wrapped in a `MaskableFrameLayout` through `MaskableTextItemViewHolder`, because `CarouselLayoutManager` rejects direct RecyclerView children that are not `MaskableFrameLayout` instances.
* The Material handler renders `EmptyView` with a plain `LinearLayoutManager` instead of Material's `CarouselLayoutManager`. `MauiCarouselRecyclerView2.SelectLayoutManager` returns a `LinearLayoutManager` while `EmptyViewAdapter` is active, because Material's full-viewport keyline mask would otherwise collapse a normally sized EmptyView.

This pr-finalize section was shortened to keep every required review section visible. Full details remain available in the pipeline build artifacts.


🏁 Report — Final Recommendation

⚠️ Final Recommendation: REQUEST CHANGES

Winner: pr-plus-reviewer

The submitted PR has a concrete loop-state inconsistency: MauiCarouselRecyclerView2 overrides IsLoopEnabled to false, yet inherited collection and loop-update paths still branch on the public Carousel.Loop value, which defaults to true. pr-plus-reviewer is the only candidate that both removes that mismatch with a focused implementation and passes the required regression scope.

Comparative ranking

Rank Candidate Implementation Regression evidence Assessment
1 pr-plus-reviewer Three Carousel.Loop checks that assume virtual adapter positions now use IsLoopEnabled. PASS — 17/17 focused Android tests. Best balance of correctness, minimal blast radius, and empirical evidence; preserves the submitted Material handler design while fixing the expert finding.
2 pr Submitted Material CarouselLayoutManager handler with real item count and forced non-loop behavior. INCONCLUSIVE Gate; tests did not run because both baseline and PR builds hit the same missing System.Diagnostics.TraceSource.dll. Concrete implementation, but the expert verified that default Loop=true can still select virtual-loop collection-update behavior against the real-count adapter.
3 try-fix-1 Proposed legacy-handler fallback for Loop=true; no patch produced. BLOCKED before validation by baseline-safety checks. Conceptually simple and preserves mature looping, but global handler registration makes per-instance routing non-trivial and there is no implementation evidence.
4 try-fix-2 Proposed rotating three-slot logical loop window; no patch produced. BLOCKED before validation by baseline-safety checks. Would preserve Material presentation and conceptual looping, but adds substantial mapping/mutation/RTL/settling complexity with no implementation or test evidence.

No candidate recorded a regression-test failure. The sole passing candidate is ranked above every inconclusive or blocked candidate, as required.

Why the winner is not the raw PR

At CarouselView.Loop=true, the raw PR's Material adapter exposes only real positions, but post-mutation recentering and equal-count replacement can still follow code written for the approximately 16,384-position virtual adapter. This can target an out-of-range virtual position or apply the wrong rebind/update sequence, leaving the displayed item, Position, or CurrentItem inconsistent. Because this is a reachable correctness defect in the submitted code, the inconclusive Gate is not the reason for requesting changes.

Winning change and validation

pr-plus-reviewer changes only MauiCarouselRecyclerView.cs, consistently using the effective IsLoopEnabled capability in the three remaining virtual-loop behavior branches. The authorized sandbox identity matched /home/vsts/work/_temp/pr-35640-pr-plus-reviewer, the immutable baseline was 652532e489b328661aad2efc49f64361b880fb8e, and git diff --check passed before validation.

The exact required command ran once from that sandbox and passed all 17 selected tests. Its output and project paths are rooted in the candidate worktree, not the raw PR worktree. No full suite or repeated repair/retest cycle was run.

Remaining uncertainty

The selected suite exercises collection additions but does not isolate equal-count replacement or runtime loop toggling. Those paths remain reasoned rather than independently demonstrated; this does not outweigh the winner's direct correction and passing required scope, but it should inform human review.


📱 UI Tests — CollectionView,Material3

Detected UI test categories: CollectionView,Material3

❌ Deep UI tests — 595 passed, 87 failed, 3 skipped across 2 categories on platform-pool agent (replaces in-process counts above). 381 new snapshot tests need a baseline PNG (added separately by a maintainer — not a regression).

🧪 UI Test Execution Results (deep, platform pool)

Category Tests Snapshot diffs
CollectionView 560/639 (79 ❌) 1 diff PNG
Material3 35/427 (8 ❌, 381 ⚠ new baseline, 3 skipped) —
🔍 AI analysis of failures — PR-related vs unrelated

🔍 AI-generated triage (GitHub Copilot CLI) — a heuristic judgement of whether each deep UI test failure is connected to this PR's changes. Verify before relying on it.

Mixed / uncertain: see the grouped assessment below.

  • ℹ Uncertain — Material3 CarouselView coverage (unknown subset of 389 tests): Android Material3 CarouselView is the one Material3 area directly changed, including its handler and test file, but the supplied failures omit those rows and cannot distinguish a PR regression from the run-wide missing-baseline pattern.
  • ● Unrelated — Non-Carousel Material3 snapshot failures (hundreds of tests): Button, Label, ImageButton, Editor, and DatePicker rows all report that Android baseline snapshots do not exist, which is a baseline-availability issue in controls the PR does not change.
  • ● Unrelated — Material3 element-wait timeouts (at least 1 test): the DatePicker dialog timeout is a recognized nondeterministic UI-automation pattern and neither DatePicker nor its Android handler is touched by this PR.
  • ● Unrelated — CollectionView failures (79 tests): the Appium click null references and scroll-index mismatches exercise CollectionView header/footer and scrolling paths, while the substantive Android changes are confined to CarouselView and the only MauiRecyclerView edit is whitespace.

Strongest signal: the failures shown span many untouched Material3 controls and overwhelmingly report absent Android baselines; only the omitted Material3 CarouselView rows warrant targeted follow-up.

❌ CollectionView — 79 failed tests
VerifyFooterTemplateWithItemsSourceObservableCollections25
System.NullReferenceException : Object reference not set to an instance of an object.
at UITest.Appium.HelperExtensions.Click(IUIElement element) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 449
   at UITest.Appium.HelperExtensions.<>c__DisplayClass2_0.<Tap>b__0() in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 36
   at UITest.Appium.HelperExtensions.<>c__DisplayClass189_0.<RunWithTimeout>b__0() in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 3136
   at System.Threading.Tasks.Task`1.InnerInvoke()
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Tas
...
VerifyHeaderStringWithItemsSourceObservableCollection5
System.NullReferenceException : Object reference not set to an instance of an object.
at UITest.Appium.HelperExtensions.Click(IUIElement element) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 449
   at UITest.Appium.HelperExtensions.<>c__DisplayClass2_0.<Tap>b__0() in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 36
   at UITest.Appium.HelperExtensions.<>c__DisplayClass189_0.<RunWithTimeout>b__0() in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 3136
   at System.Threading.Tasks.Task`1.InnerInvoke()
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Tas
...
VerifyFooterStringWithItemsLayoutVerticalGrid
System.NullReferenceException : Object reference not set to an instance of an object.
at UITest.Appium.HelperExtensions.Click(IUIElement element) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 449
   at UITest.Appium.HelperExtensions.<>c__DisplayClass2_0.<Tap>b__0() in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 36
   at UITest.Appium.HelperExtensions.<>c__DisplayClass189_0.<RunWithTimeout>b__0() in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 3136
   at System.Threading.Tasks.Task`1.InnerInvoke()
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Tas
...
VerifyGroupItemScrollToByItemWithStartPositionAndVerticalList_Carrot
Assert.That(App.WaitForElement("FirstIndexLabel").GetText(), Is.EqualTo("27"))
  String lengths are both 2. Strings differ at index 0.
  Expected: "27"
  But was:  "41"
  -----------^
at Microsoft.Maui.TestCases.Tests.CollectionView_ScrollingFeatureTests.VerifyGroupItemScrollToByItemWithStartPositionAndVerticalList_Carrot() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 1994

1)    at Microsoft.Maui.TestCases.Tests.CollectionView_ScrollingFeatureTests.VerifyGroupItemScrollToByItemWithStartPositionAndVerticalList_Carrot() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 1994
VerifyFooterStringWhenHeaderString
System.NullReferenceException : Object reference not set to an instance of an object.
at UITest.Appium.HelperExtensions.Click(IUIElement element) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 449
   at UITest.Appium.HelperExtensions.<>c__DisplayClass2_0.<Tap>b__0() in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 36
   at UITest.Appium.HelperExtensions.<>c__DisplayClass189_0.<RunWithTimeout>b__0() in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 3136
   at System.Threading.Tasks.Task`1.InnerInvoke()
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Tas
...
VerifyHeaderViewWhenBasicDataTemplateView
System.NullReferenceException : Object reference not set to an instance of an object.
at UITest.Appium.HelperExtensions.Click(IUIElement element) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 449
   at UITest.Appium.HelperExtensions.<>c__DisplayClass2_0.<Tap>b__0() in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 36
   at UITest.Appium.HelperExtensions.<>c__DisplayClass189_0.<RunWithTimeout>b__0() in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 3136
   at System.Threading.Tasks.Task`1.InnerInvoke()
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Tas
...
VerifyHeaderStringWithItemsLayoutVerticalGrid
System.NullReferenceException : Object reference not set to an instance of an object.
at UITest.Appium.HelperExtensions.Click(IUIElement element) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 449
   at UITest.Appium.HelperExtensions.<>c__DisplayClass2_0.<Tap>b__0() in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 36
   at UITest.Appium.HelperExtensions.<>c__DisplayClass189_0.<RunWithTimeout>b__0() in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 3136
   at System.Threading.Tasks.Task`1.InnerInvoke()
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Tas
...
VerifyScrollToByItemWithStartPositionAndHorizontalList_Kiwi
Assert.That(App.WaitForElement("FirstIndexLabel").GetText(), Is.EqualTo("12"))
  String lengths are both 2. Strings differ at index 0.
  Expected: "12"
  But was:  "24"
  -----------^
at Microsoft.Maui.TestCases.Tests.CollectionView_ScrollingFeatureTests.VerifyScrollToByItemWithStartPositionAndHorizontalList_Kiwi() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 2558

1)    at Microsoft.Maui.TestCases.Tests.CollectionView_ScrollingFeatureTests.VerifyScrollToByItemWithStartPositionAndHorizontalList_Kiwi() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 2558
VerifyFooterTemplateWhenFooterView
System.NullReferenceException : Object reference not set to an instance of an object.
at UITest.Appium.HelperExtensions.Click(IUIElement element) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 449
   at UITest.Appium.HelperExtensions.<>c__DisplayClass2_0.<Tap>b__0() in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 36
   at UITest.Appium.HelperExtensions.<>c__DisplayClass189_0.<RunWithTimeout>b__0() in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 3136
   at System.Threading.Tasks.Task`1.InnerInvoke()
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---

This uitests section was shortened to keep every required review section visible. Full details remain available in the pipeline build artifacts.


🧭 Next Steps — reviewer changes required

The reviewer-enhanced candidate identified changes that are not yet in the submitted PR.

Why: pr-plus-reviewer consistently applies the PR's IsLoopEnabled abstraction to the remaining virtual-loop behavior branches, preventing Material's real-count adapter from receiving virtual-loop update logic. It is the only candidate with a concrete refinement and passing evidence: all 17 required focused Android tests passed.

Address the actionable findings in this review before merging.

@kubaflo

This comment has been minimized.

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command.

@kubaflo

kubaflo commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

@Dhivya-SF4094, is this draft PR ready for review? If it still needs work, please leave it as a draft; otherwise, please mark it ready for review.

@MauiBot

MauiBot commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator

PR Test Gate

@Dhivya-SF4094 — existing-test verification; Setup did not capture a tested commit.

Result INCONCLUSIVE Platform Android


🧪 Gate analysis — click to expand

⚠ Inconclusive. The PR could not be merged with its target branch; no tests ran.

No interpretable test-group summary was produced. No additional test execution is inferred.

Setup did not capture a verified PR head; no commit is claimed as tested.

No immutable without-fix baseline was prepared.

This branch has not been deployed

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

Labels

area-controls-collectionview CollectionView, CarouselView, IndicatorView community ✨ Community Contribution do-not-merge Don't merge this PR material3 partner/syncfusion Issues / PR's with Syncfusion collaboration platform/android s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-fix-win AI found a better alternative fix than the PR s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Android] Implement material3 support for CarouselView

7 participants