Skip to content

GestureManager: Add handler-provided platform managers#33365

Open
Copilot wants to merge 13 commits into
net11.0from
copilot/create-igestureplatformmanager-interface
Open

GestureManager: Add handler-provided platform managers#33365
Copilot wants to merge 13 commits into
net11.0from
copilot/create-igestureplatformmanager-interface

Conversation

Copilot AI commented Jan 3, 2026

Copy link
Copy Markdown
Contributor

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Root Cause

GestureManager directly constructed the platform GesturePlatformManager for every handler connection. That made gesture behavior effectively hard-coded to the default manager and gave specialized handlers no lifecycle-safe way to provide a replacement for the platform view they own.

Description of Change

Adds a public IGesturePlatformManager abstraction and a public IGesturePlatformManagerProvider handler opt-in contract.

GestureManager now:

  • Uses the current handler as an IGesturePlatformManagerProvider when the handler implements the interface
  • Falls back to the existing platform GesturePlatformManager for all default handlers
  • Owns and disposes the selected manager on disconnect/reconnect, preserving existing lifecycle behavior

The provider is intentionally handler-scoped rather than service-locator based. Gesture customization is tied to the handler/platform-view instance, so the handler that owns the platform view is the right place to create the matching gesture platform manager. Because this PR targets the .NET 11 branch, both interfaces are public (added to PublicAPI.Unshipped.txt for every target framework).

Key Technical Details

  • IGesturePlatformManager : IDisposable is the shared public abstraction implemented by each platform GesturePlatformManager.
  • IGesturePlatformManagerProvider is implemented by handlers that need custom gesture behavior.
  • GestureManager still uses new GesturePlatformManager(handler) when no provider is present, so existing handlers keep the same behavior.
  • Tests cover default fallback, custom provider usage, disposal on disconnect, and creating a new manager after reconnect.

What NOT to Do (for future agents)

  • Don't register a singleton gesture manager in DI. Gesture managers are per handler connection and are disposed by GestureManager.
  • Don't use a global service factory for handler-specific gesture customization. The customization point belongs on the handler that owns the platform view.
  • Don't skip the default fallback path. Existing handlers must continue to get the default platform GesturePlatformManager automatically.

Issues Fixed

Fixes #33364

Platforms Tested

  • Controls.Core.UnitTests: GestureManagerTests, LayoutTests, animation-related tests
  • Full Controls.Core.UnitTests project

Copilot AI changed the title [WIP] Create IGesturePlatformManager interface for custom behaviors Create IGesturePlatformManager interface for custom gesture handling Jan 3, 2026
Copilot AI requested a review from PureWeen January 3, 2026 03:13
@PureWeen

Copy link
Copy Markdown
Member

/rebase

Copilot AI and others added 3 commits March 17, 2026 09:15
…pport

Co-authored-by: PureWeen <5375137+PureWeen@users.noreply.github.com>
…ract

- Add SetupHandler(IViewHandler) to IGesturePlatformManager so custom
  implementations can receive the platform view handler
- Track DI provenance in GestureManager (_gestureManagerFromDI flag)
  and skip Dispose() on DI-provided instances; the container owns their
  lifetime, not GestureManager
- Call SetupHandler(handler) on reconnect so DI singletons receive the
  new handler after a disconnect/reconnect cycle
- Add SetupHandler no-op to all built-in platform GesturePlatformManager
  classes (they initialize via constructor; the method is for custom impls)
- Add tests: DI singleton not disposed on disconnect, singleton reused
  and SetupHandler called on reconnect

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@PureWeen PureWeen force-pushed the copilot/create-igestureplatformmanager-interface branch from 35cfe01 to 4769673 Compare March 17, 2026 14:22
@github-actions

github-actions Bot commented Mar 17, 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 -- 33365

Or

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

github-actions Bot and others added 2 commits March 17, 2026 09:45
…on dispose on exception

If SetupHandler() throws, DisconnectGestures() would have called Dispose() on
the DI-owned singleton because _gestureManagerFromDI was still false. Moving
the flag assignment before SetupHandler ensures the guard is in place
regardless of whether SetupHandler succeeds or throws.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…Manager

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@kubaflo

kubaflo commented May 24, 2026

Copy link
Copy Markdown
Contributor

/review -b feature/refactor-copilot-yml

MauiBot

This comment was marked as outdated.

@MauiBot MauiBot added s/agent-review-incomplete 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 24, 2026
@kubaflo kubaflo marked this pull request as ready for review May 28, 2026 09:17
Use a factory to create handler-scoped gesture platform managers so GestureManager owns and disposes each instance on disconnect. This avoids reusing DI-provided managers across handler connections and removes the setup-only lifecycle hook.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@kubaflo

kubaflo commented May 28, 2026

Copy link
Copy Markdown
Contributor

/review -b feature/refactor-copilot-yml

@MauiBot MauiBot added s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates and removed s/agent-fix-win AI found a better alternative fix than the PR labels May 28, 2026
@kubaflo kubaflo dismissed MauiBot’s stale review June 9, 2026 19:17

Superseded by a newer MauiBot review run.

@kubaflo

kubaflo commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

/review rerun

@github-actions github-actions Bot added the s/agent-ready-for-rerun AI review has new PR activity and is ready for rerun label Jun 9, 2026
@kubaflo

kubaflo commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

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

PureWeen pushed a commit that referenced this pull request Jun 10, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

## Summary

- Gives the normal `/review` trigger job `pull-requests: write`,
matching the rerun job, so it can apply the `s/agent-review-in-progress`
lock label before dispatching the AzDO pipeline.
- Logs the actual `gh api` response when adding a label fails, instead
of suppressing stderr and returning only a generic failure.

## Why this broke

`/review -b feature/enhanced-reviewer` was still parsed correctly; the
failure was introduced by a default-branch workflow change. The last
successful trigger on PR #33365 ran on workflow SHA `c389325e`, before
the `Set review in-progress lock` step existed. After `main` moved to
`dd5b6d2`, the normal `/review` path started applying
`s/agent-review-in-progress` before dispatching AzDO, but that job still
only requested `pull-requests: read`.

The rerun path already requested `pull-requests: write` and could apply
labels successfully. This PR aligns the normal `/review` path with that
permission so the lock label can be applied and the AzDO pipeline
dispatch can proceed.

## Validation

- `git diff --check`
- Parsed `.github/workflows/review-trigger.yml` with Ruby YAML
- Fake `gh` success/failure checks for `Add-Label`
- `Invoke-Pester .github/scripts -CI`
- `Invoke-Pester .github/skills -CI`

## Fixes

- Fixes `/review -b feature/enhanced-reviewer` failing before AzDO
dispatch at `Set review in-progress lock`.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@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 new PR activity and is ready for rerun labels Jun 10, 2026
@dotnet dotnet deleted a comment from github-actions Bot Jun 10, 2026
@kubaflo

kubaflo commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

/review rerun

@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

@copilot — new AI review results are available based on this last commit: 4810c80.
Use handler provider for gesture platform managers To request a fresh review after new comments or commits, comment /review rerun.

Gate Failed Code Review Needs Changes Confidence High Platform Android

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

Gate Result: ❌ FAILED

Platform: ANDROID · Base: main · Merge base: dd5b6d2e

🩺 Base branch does not compile — the without-fix build failed. The gate's "does the test fail without the fix" check is unreliable here; this usually means main is broken or a merge-base file went missing. Investigate before trusting this gate.

Test Without Fix (expect FAIL) With Fix (expect PASS)
🧪 AnimationReadyHandler AnimationReadyHandler 🛠️ BUILD ERROR 🔍 NO MATCH
🧪 GestureManagerTests GestureManagerTests 🛠️ BUILD ERROR ✅ PASS — 27s
🧪 LayoutTests LayoutTests 🛠️ BUILD ERROR ✅ PASS — 29s
🔴 Without fix — 🧪 AnimationReadyHandler: 🛠️ BUILD ERROR · 153s
  Determining projects to restore...
  Restored /home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj (in 7.43 sec).
  Restored /home/vsts/work/1/s/src/TestUtils/src/TestUtils/TestUtils.csproj (in 194 ms).
  Restored /home/vsts/work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 241 ms).
  Restored /home/vsts/work/1/s/src/Essentials/src/Essentials.csproj (in 448 ms).
  Restored /home/vsts/work/1/s/src/Controls/src/Xaml/Controls.Xaml.csproj (in 10.7 sec).
  Restored /home/vsts/work/1/s/src/Core/src/Core.csproj (in 184 ms).
  Restored /home/vsts/work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 44 ms).
  Restored /home/vsts/work/1/s/src/Core/maps/src/Maps.csproj (in 1.59 sec).
  Restored /home/vsts/work/1/s/src/Controls/Maps/src/Controls.Maps.csproj (in 1.45 sec).
  1 of 10 projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0/Microsoft.Maui.Controls.Xaml.dll
  Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0/Microsoft.Maui.Maps.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0/Microsoft.Maui.Controls.Maps.dll
  TestUtils -> /home/vsts/work/1/s/artifacts/bin/TestUtils/Debug/netstandard2.0/Microsoft.Maui.TestUtils.dll
/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Gestures/GestureManagerTests.cs(140,17): error CS1503: Argument 1: cannot convert from 'Microsoft.Maui.Controls.Platform.IGesturePlatformManager' to 'System.DateTime' [/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj]
/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Gestures/GestureManagerTests.cs(140,32): error CS1503: Argument 2: cannot convert from 'Microsoft.Maui.Controls.Platform.GesturePlatformManager' to 'System.DateTime' [/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj]
/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Gestures/GestureManagerTests.cs(176,17): error CS1503: Argument 1: cannot convert from 'Microsoft.Maui.Controls.Platform.IGesturePlatformManager' to 'System.DateTime' [/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj]
/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Gestures/GestureManagerTests.cs(176,32): error CS1503: Argument 2: cannot convert from 'Microsoft.Maui.Controls.Platform.GesturePlatformManager' to 'System.DateTime' [/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj]
/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Gestures/GestureManagerTests.cs(188,17): error CS1503: Argument 1: cannot convert from 'Microsoft.Maui.Controls.Platform.IGesturePlatformManager' to 'System.DateTime' [/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj]
/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Gestures/GestureManagerTests.cs(188,33): error CS1503: Argument 2: cannot convert from 'Microsoft.Maui.Controls.Platform.GesturePlatformManager' to 'System.DateTime' [/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj]

🟢 With fix — 🧪 AnimationReadyHandler: 🔍 NO MATCH · 128s
  Determining projects to restore...
  All projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0/Microsoft.Maui.Maps.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0/Microsoft.Maui.Controls.Xaml.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0/Microsoft.Maui.Controls.Maps.dll
  TestUtils -> /home/vsts/work/1/s/artifacts/bin/TestUtils/Debug/netstandard2.0/Microsoft.Maui.TestUtils.dll
  Controls.Core.UnitTests -> /home/vsts/work/1/s/artifacts/bin/Controls.Core.UnitTests/Debug/net10.0/Microsoft.Maui.Controls.Core.UnitTests.dll
Test run for /home/vsts/work/1/s/artifacts/bin/Controls.Core.UnitTests/Debug/net10.0/Microsoft.Maui.Controls.Core.UnitTests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.25]   Discovering: Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:02.52]   Discovered:  Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:02.54]   Starting:    Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:02.56]   Finished:    Microsoft.Maui.Controls.Core.UnitTests
No test matches the given testcase filter `AnimationReadyHandler` in /home/vsts/work/1/s/artifacts/bin/Controls.Core.UnitTests/Debug/net10.0/Microsoft.Maui.Controls.Core.UnitTests.dll


🔴 Without fix — 🧪 GestureManagerTests: 🛠️ BUILD ERROR · 40s
  Determining projects to restore...
  All projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0/Microsoft.Maui.Maps.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0/Microsoft.Maui.Controls.Xaml.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0/Microsoft.Maui.Controls.Maps.dll
  TestUtils -> /home/vsts/work/1/s/artifacts/bin/TestUtils/Debug/netstandard2.0/Microsoft.Maui.TestUtils.dll
/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Gestures/GestureManagerTests.cs(140,17): error CS1503: Argument 1: cannot convert from 'Microsoft.Maui.Controls.Platform.IGesturePlatformManager' to 'System.DateTime' [/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj]
/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Gestures/GestureManagerTests.cs(140,32): error CS1503: Argument 2: cannot convert from 'Microsoft.Maui.Controls.Platform.GesturePlatformManager' to 'System.DateTime' [/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj]
/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Gestures/GestureManagerTests.cs(176,17): error CS1503: Argument 1: cannot convert from 'Microsoft.Maui.Controls.Platform.IGesturePlatformManager' to 'System.DateTime' [/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj]
/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Gestures/GestureManagerTests.cs(176,32): error CS1503: Argument 2: cannot convert from 'Microsoft.Maui.Controls.Platform.GesturePlatformManager' to 'System.DateTime' [/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj]
/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Gestures/GestureManagerTests.cs(188,17): error CS1503: Argument 1: cannot convert from 'Microsoft.Maui.Controls.Platform.IGesturePlatformManager' to 'System.DateTime' [/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj]
/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Gestures/GestureManagerTests.cs(188,33): error CS1503: Argument 2: cannot convert from 'Microsoft.Maui.Controls.Platform.GesturePlatformManager' to 'System.DateTime' [/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj]

🟢 With fix — 🧪 GestureManagerTests: PASS ✅ · 27s
  Determining projects to restore...
  All projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0/Microsoft.Maui.Maps.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0/Microsoft.Maui.Controls.Xaml.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0/Microsoft.Maui.Controls.Maps.dll
  TestUtils -> /home/vsts/work/1/s/artifacts/bin/TestUtils/Debug/netstandard2.0/Microsoft.Maui.TestUtils.dll
  Controls.Core.UnitTests -> /home/vsts/work/1/s/artifacts/bin/Controls.Core.UnitTests/Debug/net10.0/Microsoft.Maui.Controls.Core.UnitTests.dll
Test run for /home/vsts/work/1/s/artifacts/bin/Controls.Core.UnitTests/Debug/net10.0/Microsoft.Maui.Controls.Core.UnitTests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.52]   Discovering: Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:04.52]   Discovered:  Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:04.54]   Starting:    Microsoft.Maui.Controls.Core.UnitTests
  Passed HandlerProviderCreatesNewManagerAfterReconnect [333 ms]
  Passed UsesDefaultGesturePlatformManagerWhenHandlerDoesNotProvideCustomManager [7 ms]
  Passed PlatformManagerChangesWhenContainerViewChanged [36 ms]
  Passed DoesntConnectWithOnlyWindowSet [< 1 ms]
  Passed ConnectsWithOnlyHandlerSet [2 ms]
  Passed PlatformManagerChangesWhenHandlerChanged [< 1 ms]
  Passed UsesCustomGesturePlatformManagerWhenHandlerProvidesOne [< 1 ms]
  Passed ConnectsWithWindowAndHandlerSet [5 ms]
  Passed HandlerProvidedManagerIsDisposedOnDisconnect [2 ms]
[xUnit.net 00:00:05.07]   Finished:    Microsoft.Maui.Controls.Core.UnitTests
  Passed DisconnectsWhenWindowIsRemoved [< 1 ms]
  Passed DisconnectsWhenHandlerIsRemoved [< 1 ms]

Test Run Successful.
Total tests: 11
     Passed: 11
 Total time: 6.6392 Seconds

🔴 Without fix — 🧪 LayoutTests: 🛠️ BUILD ERROR · 37s
  Determining projects to restore...
  All projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0/Microsoft.Maui.Maps.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0/Microsoft.Maui.Controls.Maps.dll
  ##vso[build.updatebuildnumber]10.0.80-ci+azdo.14340017
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0/Microsoft.Maui.Controls.Xaml.dll
  TestUtils -> /home/vsts/work/1/s/artifacts/bin/TestUtils/Debug/netstandard2.0/Microsoft.Maui.TestUtils.dll
/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Gestures/GestureManagerTests.cs(140,17): error CS1503: Argument 1: cannot convert from 'Microsoft.Maui.Controls.Platform.IGesturePlatformManager' to 'System.DateTime' [/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj]
/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Gestures/GestureManagerTests.cs(140,32): error CS1503: Argument 2: cannot convert from 'Microsoft.Maui.Controls.Platform.GesturePlatformManager' to 'System.DateTime' [/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj]
/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Gestures/GestureManagerTests.cs(176,17): error CS1503: Argument 1: cannot convert from 'Microsoft.Maui.Controls.Platform.IGesturePlatformManager' to 'System.DateTime' [/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj]
/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Gestures/GestureManagerTests.cs(176,32): error CS1503: Argument 2: cannot convert from 'Microsoft.Maui.Controls.Platform.GesturePlatformManager' to 'System.DateTime' [/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj]
/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Gestures/GestureManagerTests.cs(188,17): error CS1503: Argument 1: cannot convert from 'Microsoft.Maui.Controls.Platform.IGesturePlatformManager' to 'System.DateTime' [/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj]
/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Gestures/GestureManagerTests.cs(188,33): error CS1503: Argument 2: cannot convert from 'Microsoft.Maui.Controls.Platform.GesturePlatformManager' to 'System.DateTime' [/home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj]

🟢 With fix — 🧪 LayoutTests: PASS ✅ · 29s

(truncated to last 15,000 chars)

Size(relX: 0.20000000000000001, relY: 0.20000000000000001, relHeight: 0, relWidth: 0.5) [3 ms]
  Passed RelativePositionRelativeSize(relX: 0, relY: 0.20000000000000001, relHeight: 0, relWidth: 0) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 1, relY: 1, relHeight: 0.20000000000000001, relWidth: 0) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.5, relY: 0.20000000000000001, relHeight: 0, relWidth: 1) [1 ms]
  Passed RelativePositionRelativeSize(relX: 0.20000000000000001, relY: 0, relHeight: 0.20000000000000001, relWidth: 0) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0, relY: 0.5, relHeight: 1, relWidth: 0) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.20000000000000001, relY: 1, relHeight: 1, relWidth: 0.5) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.5, relY: 0, relHeight: 0.5, relWidth: 0.20000000000000001) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.20000000000000001, relY: 0, relHeight: 0.5, relWidth: 0) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.20000000000000001, relY: 0.20000000000000001, relHeight: 1, relWidth: 0.20000000000000001) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.20000000000000001, relY: 1, relHeight: 0.5, relWidth: 1) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0, relY: 0, relHeight: 1, relWidth: 1) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.20000000000000001, relY: 0.5, relHeight: 0.5, relWidth: 0.5) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 1, relY: 1, relHeight: 1, relWidth: 0.20000000000000001) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 1, relY: 0.20000000000000001, relHeight: 0.5, relWidth: 0) [2 ms]
  Passed RelativePositionRelativeSize(relX: 1, relY: 0.20000000000000001, relHeight: 1, relWidth: 1) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0, relY: 0.5, relHeight: 1, relWidth: 0.5) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.5, relY: 0.20000000000000001, relHeight: 1, relWidth: 0.20000000000000001) [2 ms]
  Passed RelativePositionRelativeSize(relX: 0, relY: 1, relHeight: 0.5, relWidth: 1) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 1, relY: 0, relHeight: 0.5, relWidth: 0.20000000000000001) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.5, relY: 0.5, relHeight: 0.5, relWidth: 0.5) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 1, relY: 0.5, relHeight: 0.5, relWidth: 0.20000000000000001) [2 ms]
  Passed RelativePositionRelativeSize(relX: 0.20000000000000001, relY: 0, relHeight: 0, relWidth: 1) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0, relY: 0, relHeight: 0, relWidth: 1) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.20000000000000001, relY: 1, relHeight: 1, relWidth: 0.20000000000000001) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.20000000000000001, relY: 1, relHeight: 0.20000000000000001, relWidth: 0) [3 ms]
  Passed RelativePositionRelativeSize(relX: 0, relY: 1, relHeight: 0.5, relWidth: 0.5) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0, relY: 1, relHeight: 0, relWidth: 0) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0, relY: 0.20000000000000001, relHeight: 0.5, relWidth: 1) [3 ms]
  Passed RelativePositionRelativeSize(relX: 0.5, relY: 0.5, relHeight: 1, relWidth: 0.20000000000000001) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.20000000000000001, relY: 1, relHeight: 0.5, relWidth: 0) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.20000000000000001, relY: 0.5, relHeight: 0, relWidth: 0.20000000000000001) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.5, relY: 0.20000000000000001, relHeight: 0.5, relWidth: 0.5) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.20000000000000001, relY: 0.5, relHeight: 0.20000000000000001, relWidth: 0.20000000000000001) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 1, relY: 0, relHeight: 0.20000000000000001, relWidth: 0.5) [1 ms]
  Passed RelativePositionRelativeSize(relX: 0, relY: 0, relHeight: 0.20000000000000001, relWidth: 0.5) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.20000000000000001, relY: 0.20000000000000001, relHeight: 0.20000000000000001, relWidth: 0.20000000000000001) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.20000000000000001, relY: 0.5, relHeight: 0.20000000000000001, relWidth: 0) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 1, relY: 0, relHeight: 0, relWidth: 0.20000000000000001) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0, relY: 0, relHeight: 0.20000000000000001, relWidth: 0.20000000000000001) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.5, relY: 0, relHeight: 0, relWidth: 1) [1 ms]
  Passed RelativePositionRelativeSize(relX: 0, relY: 0.5, relHeight: 0.5, relWidth: 0) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0, relY: 0, relHeight: 0.5, relWidth: 0.20000000000000001) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 1, relY: 0, relHeight: 0.5, relWidth: 0.5) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0, relY: 0, relHeight: 0.20000000000000001, relWidth: 0) [2 ms]
  Passed RelativePositionRelativeSize(relX: 0, relY: 0.5, relHeight: 0, relWidth: 0.20000000000000001) [103 ms]
  Passed RelativePositionRelativeSize(relX: 0.20000000000000001, relY: 0.5, relHeight: 1, relWidth: 0.20000000000000001) [4 ms]
  Passed RelativePositionRelativeSize(relX: 0.20000000000000001, relY: 1, relHeight: 1, relWidth: 0) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.20000000000000001, relY: 1, relHeight: 0.20000000000000001, relWidth: 0.20000000000000001) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 1, relY: 1, relHeight: 1, relWidth: 1) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 1, relY: 0, relHeight: 1, relWidth: 0.5) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0, relY: 1, relHeight: 0, relWidth: 0.20000000000000001) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.5, relY: 0.20000000000000001, relHeight: 0.20000000000000001, relWidth: 0) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.20000000000000001, relY: 0, relHeight: 0.5, relWidth: 0.5) [1 ms]
  Passed RelativePositionRelativeSize(relX: 1, relY: 0.20000000000000001, relHeight: 0.5, relWidth: 0.5) [1 ms]
  Passed RelativePositionRelativeSize(relX: 1, relY: 0, relHeight: 0, relWidth: 0.5) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.20000000000000001, relY: 1, relHeight: 0, relWidth: 0.20000000000000001) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 1, relY: 0.20000000000000001, relHeight: 0, relWidth: 1) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.5, relY: 1, relHeight: 1, relWidth: 0.20000000000000001) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.5, relY: 0.5, relHeight: 0, relWidth: 1) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.5, relY: 0.20000000000000001, relHeight: 1, relWidth: 0.5) [3 ms]
  Passed RelativePositionRelativeSize(relX: 0.5, relY: 0, relHeight: 0.20000000000000001, relWidth: 0.5) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.20000000000000001, relY: 0.20000000000000001, relHeight: 0, relWidth: 0.20000000000000001) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 1, relY: 1, relHeight: 0.20000000000000001, relWidth: 0.20000000000000001) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.5, relY: 0.20000000000000001, relHeight: 0.20000000000000001, relWidth: 0.20000000000000001) [3 ms]
  Passed RelativePositionRelativeSize(relX: 0.5, relY: 0.5, relHeight: 0, relWidth: 0.20000000000000001) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.20000000000000001, relY: 1, relHeight: 0, relWidth: 0) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 1, relY: 1, relHeight: 0.20000000000000001, relWidth: 0.5) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 0.5, relY: 0.5, relHeight: 0.5, relWidth: 0.20000000000000001) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 1, relY: 0.20000000000000001, relHeight: 0.20000000000000001, relWidth: 0.20000000000000001) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 1, relY: 0, relHeight: 0, relWidth: 0) [< 1 ms]
  Passed RelativePositionRelativeSize(relX: 1, relY: 1, relHeight: 0.5, relWidth: 1) [2 ms]
  Passed RelativePositionRelativeSize(relX: 0, relY: 1, relHeight: 0, relWidth: 0.5) [2 ms]
  Passed TestBoundsTypeConverter(culture: "en-US") [47 ms]
  Passed TestBoundsTypeConverter(culture: "tr-TR") [< 1 ms]
  Passed RelativePositionAbsoluteSize(width: 30, height: 40, relX: 0.20000000000000001, relY: 0.29999999999999999) [14 ms]
  Passed RelativePositionAbsoluteSize(width: 35, height: 45, relX: 0, relY: 0) [4 ms]
  Passed RelativePositionAbsoluteSize(width: 35, height: 45, relX: 1, relY: 1) [< 1 ms]
  Passed RelativePositionAbsoluteSize(width: 35, height: 45, relX: 0.5, relY: 0.5) [< 1 ms]
  Passed AbsolutePositionRelativeSize [8 ms]
  Passed SizeRequestWithNormalChild [16 ms]
  Passed SizeRequestWithRelativeChild [10 ms]
  Passed SizeRequestWithRelativePositionChild [2 ms]
  Passed Constructor [5 ms]
  Passed AbsolutePositionAndSizeUsingRectangle [6 ms]
  Passed SizeRequestWithRelativeSizeChild [< 1 ms]
  Passed MeasureInvalidatedFiresWhenBoundsChanged [1 ms]
  Passed MeasureInvalidatedFiresWhenFlagsChanged [< 1 ms]
  Passed LayoutIsGarbageCollectedAfterItsRemoved [251 ms]
  Passed ItemTemplateSelectorIsSet [26 ms]
  Passed ChangingTemplateRecreatesChildren [17 ms]
  Passed ChangingItemsRemovesExceedingChildren [5 ms]
  Passed TracksRemove [5 ms]
  Passed TracksInsert [1 ms]
  Passed ChangingItemMaintainingTemplateUpdatesBindingContextOnly [15 ms]
  Passed AddsEmptyViewWhenRemovingRemainingItem [3 ms]
  Passed ItemViewBindingContextIsSetToNullOnClear [1 ms]
  Passed ItemsSourceTakePrecendenceOverLayoutChildren [3 ms]
  Passed WorksWithDuplicateItems [4 ms]
  Passed TracksReplace [2 ms]
  Passed BindableLayout Still Updates after a GC [83 ms]
  Passed DontTrackAfterItemsSourceChanged [1 ms]
  Passed TracksClear [1 ms]
  Passed ThrowsExceptionOnUsingDataTemplateSelectorForItemTemplate [6 ms]
  Passed DoesNotLeak [98 ms]
  Passed ChangingItemsMaintainingTemplateUpdatesBindingContextOnly [6 ms]
  Passed TracksMove [3 ms]
  Passed WorksWithNullItems [15 ms]
  Passed ItemViewBindingContextIsSetToNullOnRemove [< 1 ms]
  Passed ValidateBindableProperties [7 ms]
  Passed ItemTemplateTakesPrecendenceOverItemTemplateSelector [3 ms]
  Passed ContainerIsPassedInSelectTemplate [1 ms]
  Passed TracksRemoveAll [4 ms]
  Passed EmptyViewTemplateContentInheritsLayoutBindingContext [1 ms]
  Passed RemovesEmptyViewWhenAddingTheFirstItem [1 ms]
  Passed TracksEmpty [< 1 ms]
  Passed TracksAdd [< 1 ms]
  Passed BindableLayout disconnects handlers when removing views [207 ms]
  Passed TracksNull [1 ms]
  Passed ItemTemplateIsSet [8 ms]
  Passed ThreePassLayoutWithExpressions [63 ms]
  Passed SimpleExpressionLayout [2 ms]
  Passed ViewRelativeLayout [15 ms]
  Passed ViewRelativeLayoutWithExpressions [16 ms]
  Passed RelativeLayoutContentShouldBeAppeared [10 ms]
  Passed ThreePassLayout [11 ms]
  Passed SimpleBoundsSizing [1 ms]
  Passed ViewRelativeToMultipleViews [5 ms]
  Passed UnconstrainedSize [4 ms]
  Passed LayoutIsUpdatedWhenConstraintsChange [4 ms]
  Passed ExpressionRelativeToMultipleViews [8 ms]
  Passed ThrowsWithUnsolvableConstraints [4 ms]
  Passed SimpleLayout [4 ms]
  Passed BoundsUpdatedIfConstraintsChangedWhileNotParented [3 ms]
  Passed ChildAddedBeforeLayoutChildrenAfterInitialLayout [5 ms]
  Passed BoundsDefaultsAttachedProperty [1 ms]
  Passed BoundsDefaultsConsistentForNewChildren [14 ms]
  Passed BoundsDefaultsRegularProperty [< 1 ms]
  Passed GrowItemsPreserveNaturalSizeAndDistributeFreeSpaceEqually_Issue34464 [46 ms]
  Passed FlexLayoutRecognizesVisibilityChange [19 ms]
  Passed UnconstrainedWidthChildrenHaveWidth [9 ms]
  Passed UnconstrainedMeasureHonorsFlexDirection(widthConstraint: Infinity, heightConstraint: 400, flexDirection: RowReverse) [2 ms]
  Passed UnconstrainedMeasureHonorsFlexDirection(widthConstraint: 400, heightConstraint: Infinity, flexDirection: ColumnReverse) [< 1 ms]
  Passed UnconstrainedMeasureHonorsFlexDirection(widthConstraint: Infinity, heightConstraint: 400, flexDirection: Row) [< 1 ms]
  Passed UnconstrainedMeasureHonorsFlexDirection(widthConstraint: 400, heightConstraint: Infinity, flexDirection: Column) [2 ms]
  Passed FlexLayoutPaddingShouldBeAppliedCorrectly_ColumnDirection [1 ms]
  Passed ArrangeOnlyPassUsesUpdatedWidthRequest [< 1 ms]
  Passed FlexLayoutMeasuresImagesUnconstrained [2 ms]
  Passed UnconstrainedHeightChildrenHaveHeight [< 1 ms]
  Passed ArrangeOnlyPassFallsBackToDesiredSizeWhenWidthRequestCleared [< 1 ms]
  Passed FlexLayoutPaddingShouldBeAppliedCorrectly_RowDirection [< 1 ms]
  Passed ArrangeOnlyPassUsesDesiredSizeWhenNoWidthRequest [1 ms]
  Passed ArrangeOnlyPassUsesUpdatedHeightRequest [< 1 ms]
  Passed ColumnDefinitionDoesNotLeak [62 ms]
  Passed ChangingRowSpacingInvalidatesGrid [28 ms]
  Passed RowDefinitionsGetBindingContext [1 ms]
  Passed RowDefinitionDoesNotLeak [69 ms]
  Passed RemovedMauiViewsHaveNoRowColumnInfo [7 ms]
  Passed AddedMauiViewGetsDefaultRowAndColumn [< 1 ms]
  Passed ChangingChildColumnInvalidatesGrid [2 ms]
  Passed ColumnDefinitionsGetBindingContext [4 ms]
  Passed ChangingChildRowInvalidatesGrid [2 ms]
  Passed AddedViewGetsDefaultRowAndColumn [< 1 ms]
  Passed ChangingColumnSpacingInvalidatesGrid [< 1 ms]
  Passed AddCallsCorrectHandlerMethod(TLayout: typeof(Microsoft.Maui.Controls.StackLayout)) [19 ms]
  Passed AddCallsCorrectHandlerMethod(TLayout: typeof(Microsoft.Maui.Controls.Grid)) [2 ms]
  Passed AddCallsCorrectHandlerMethod(TLayout: typeof(Microsoft.Maui.Controls.VerticalStackLayout)) [< 1 ms]
  Passed AddCallsCorrectHandlerMethod(TLayout: typeof(Microsoft.Maui.Controls.HorizontalStackLayout)) [1 ms]
  Passed RemoveCallsCorrectHandlerMethod(TLayout: typeof(Microsoft.Maui.Controls.Grid)) [4 ms]
  Passed RemoveCallsCorrectHandlerMethod(TLayout: typeof(Microsoft.Maui.Controls.HorizontalStackLayout)) [< 1 ms]
  Passed RemoveCallsCorrectHandlerMethod(TLayout: typeof(Microsoft.Maui.Controls.StackLayout)) [< 1 ms]
  Passed RemoveCallsCorrectHandlerMethod(TLayout: typeof(Microsoft.Maui.Controls.VerticalStackLayout)) [4 ms]
  Passed InsertCallsCorrectHandlerMethod(TLayout: typeof(Microsoft.Maui.Controls.StackLayout)) [1 ms]
  Passed InsertCallsCorrectHandlerMethod(TLayout: typeof(Microsoft.Maui.Controls.Grid)) [< 1 ms]
  Passed InsertCallsCorrectHandlerMethod(TLayout: typeof(Microsoft.Maui.Controls.HorizontalStackLayout)) [< 1 ms]
  Passed InsertCallsCorrectHandlerMethod(TLayout: typeof(Microsoft.Maui.Controls.VerticalStackLayout)) [2 ms]
  Passed CanUseFactoryForAlternateManager [20 ms]
[xUnit.net 00:00:06.96]   Finished:    Microsoft.Maui.Controls.Core.UnitTests
  Passed UsingIndexUpdatesParent [1 ms]
  Passed FactoryCanPuntAndUseOriginalType [7 ms]
  Passed FactoryCanCustomizeBasedOnLayoutType [1 ms]
  Passed ClearUpdatesParent [< 1 ms]

Test Run Successful.
Total tests: 364
     Passed: 364
 Total time: 8.4179 Seconds

⚠️ Failure Details

  • 🛠️ AnimationReadyHandler without fix: build failed before tests could run
    • /home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Gestures/GestureManagerTests.cs(140,17): error CS1503: Argument 1: cannot convert from 'Microsoft.Maui.Controls.Platform.IGesturePlatformManager' ...
  • 🛠️ GestureManagerTests without fix: build failed before tests could run
    • /home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Gestures/GestureManagerTests.cs(140,17): error CS1503: Argument 1: cannot convert from 'Microsoft.Maui.Controls.Platform.IGesturePlatformManager' ...
  • 🛠️ LayoutTests without fix: build failed before tests could run
    • /home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Gestures/GestureManagerTests.cs(140,17): error CS1503: Argument 1: cannot convert from 'Microsoft.Maui.Controls.Platform.IGesturePlatformManager' ...
  • 🔍 AnimationReadyHandler with fix: test filter matched 0 tests
    • filter: AnimationReadyHandler
📁 Fix files reverted (7 files)
  • eng/pipelines/ci-copilot.yml
  • src/Controls/src/Core/Platform/GestureManager/GestureManager.cs
  • src/Controls/src/Core/Platform/GestureManager/GesturePlatformManager.Android.cs
  • src/Controls/src/Core/Platform/GestureManager/GesturePlatformManager.Standard.cs
  • src/Controls/src/Core/Platform/GestureManager/GesturePlatformManager.Tizen.cs
  • src/Controls/src/Core/Platform/GestureManager/GesturePlatformManager.Windows.cs
  • src/Controls/src/Core/Platform/GestureManager/GesturePlatformManager.iOS.cs

New files (not reverted):

  • src/Controls/src/Core/Platform/GestureManager/IGesturePlatformManager.cs
  • src/Controls/src/Core/Platform/GestureManager/IGesturePlatformManagerProvider.cs

UI Tests

Full UI test matrix will run (no specific categories detected from PR changes).


Pre-Flight — Context & Validation

Issue: #33364 - Create IGesturePlatformManager so users can replace the behavior of our GesturePlatformManager a
PR: #33365 - GestureManager: Add handler-provided platform managers
Platforms Affected: Android, iOS/MacCatalyst, Windows, Tizen, Standard
Files Changed: 8 implementation, 3 test

Key Findings

  • The linked issue asks for an internal gesture platform manager abstraction now, with a TODO to make it public in .NET 11.
  • The PR implements a handler-scoped customization point: handlers may implement IGesturePlatformManagerProvider; otherwise GestureManager falls back to the platform GesturePlatformManager.
  • Android impact is lifecycle-sensitive because GesturePlatformManager.Android owns touch/key subscriptions, lazy gesture detectors, and RecyclerView touch listeners.
  • PR discussion has no inline review comments; comments are mostly review/CI commands.
  • Gate result was already completed separately and failed because tests did not behave as expected; gate was not rerun here.

Code Review Summary

Verdict: LGTM
Confidence: high
Errors: 0 | Warnings: 0 | Suggestions: 0

Key code review findings:

  • No findings. The independent code review found the handler-provider implementation lifecycle-safe and consistent with the PR narrative.

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #33365 Add internal IGesturePlatformManager and handler opt-in IGesturePlatformManagerProvider; GestureManager uses the provider before default fallback. ❌ FAILED (Gate) GestureManager.cs, platform managers, new interfaces, unit tests Original PR; gate failure was pre-existing and not rerun.

Code Review — Deep Analysis

Code Review — PR #33365

Independent Assessment

What this changes: Introduces an internal IGesturePlatformManager abstraction and lets GestureManager ask the current handler for a custom gesture platform manager via IGesturePlatformManagerProvider, while retaining the existing per-platform default manager fallback and disposal lifecycle.
Inferred motivation: Specialized handlers need to own or replace gesture behavior tied to their platform view without changing the default gesture manager path for all controls.

Reconciliation with PR Narrative

Author claims: The PR adds an internal handler-scoped opt-in contract, preserves default behavior, disposes selected managers on disconnect/reconnect, and intentionally defers public API exposure to .NET 11.
Agreement/disagreement: This matches the code. The linked issue mentioned service-based lookup, but the handler-scoped provider is consistent with the lifecycle and platform-view ownership concerns described in the PR.

Findings

No findings.

Devil's Advocate

I checked whether custom managers could miss disposal, whether default platform managers still compile against the new interface, and whether existing gesture consumers depend on the concrete GesturePlatformManager type. The change is narrow: the interface only requires Dispose, all default platform managers already implement compatible disposal, and call sites outside tests do not require concrete members from GestureManager.GesturePlatformManager. CI check-runs are successful; targeted GestureManagerTests/LayoutTests also passed locally after restore.

Verdict: LGTM

Confidence: high
Summary: The implementation preserves existing default behavior while adding a lifecycle-safe internal customization point. I found no concrete correctness, lifecycle, or platform-specific issues in the modified lines.


Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 maui-expert-reviewer Resolve an internal IGesturePlatformManagerFactory from handler.MauiContext.Services; factory creates per-handler managers. ❌ FAILED 2 files Failed provider-specific regression tests because the handler provider was bypassed.
2 maui-expert-reviewer Extract provider/default creation policy to GesturePlatformManagerResolver.Create(handler) while preserving IGesturePlatformManagerProvider. ✅ PASSED 2 files Passes current tests; cleaner separation of creation policy from lifecycle management.
PR PR #33365 Handler implements IGesturePlatformManagerProvider; GestureManager uses it before default fallback. ❌ FAILED (Gate) 8 implementation files, 3 test files Gate result was supplied by caller and not rerun.

Cross-Pollination

Model Round New Ideas? Details
maui-expert-reviewer 1 Yes Candidate 1 proposed DI factory; failure shows compatibility with current provider tests is required.
maui-expert-reviewer 2 No No further meaningfully different ideas likely to pass current provider-specific tests; remaining options are resolver-style refactors or bypass provider tests.

Exhausted: Yes
Selected Fix: Candidate #2 — it passes the targeted regression tests and modestly improves separation of lifecycle management from manager creation policy. It is not a fundamentally different extensibility model from the PR fix, so its advantage is maintainability rather than behavior.


Report — Final Recommendation

Comparative Candidate Report

Candidates

Rank Candidate Regression result Assessment
1 try-fix-2 PASS Preserves the PR's handler-provider contract while extracting manager creation into GesturePlatformManagerResolver.Create(handler). It passed the targeted regression command with 375/375 tests passing and improves separation of creation policy from lifecycle management.
2 pr FAILED gate The raw PR fix is behaviorally sound in the with-fix run and the expert reviewer found no lifecycle or Android regressions, but the supplied gate result is failed and failed candidates must rank below passing candidates.
3 pr-plus-reviewer FAILED by equivalence to try-fix-1 Incorporates the expert reviewer's services/factory API-shape feedback, but this bypasses IGesturePlatformManagerProvider and fails the provider-specific regression tests.
4 try-fix-1 FAILED Proposes the same DI factory direction as the expert feedback. It failed 3 tests because the handler-provided manager was no longer selected or disposed.

Analysis

pr introduces the requested internal IGesturePlatformManager abstraction and lets handlers provide per-connection platform managers. The expert review found one meaningful concern: the linked issue describes a Services replacement path, while the PR implements handler-level replacement. That concern needs maintainer alignment, but it is not a lifecycle defect.

pr-plus-reviewer applies that feedback as a service-resolved factory. However, STEP 5a already tested that design as try-fix-1, and it failed the current regression suite because the provider contract was bypassed. Under the required ranking rule, it cannot beat a passing candidate.

try-fix-2 keeps the PR's observable behavior and tests intact, but moves the selection logic out of GestureManager. This is a small architectural improvement over the raw PR because lifecycle management stays in GestureManager while creation policy is isolated and testable.

Winner

try-fix-2 is the winning candidate. It is the only candidate that both passed the regression tests and improves the implementation structure without changing the accepted handler-provider behavior.


Future Action — alternative fix proposed (try-fix-2)

Automated review — alternative fix proposed

The expert-reviewer evaluation compared the PR fix against automatically generated candidates and selected try-fix-2 as the strongest fix.

Why: try-fix-2 is the only candidate that passed the targeted regression tests while preserving the PR's handler-provider behavior. It also improves the PR implementation by moving gesture platform manager creation policy out of GestureManager and into a resolver.

Please consider applying the candidate diff below (or use it as guidance). Once you push an update, this workflow will re-trigger and re-evaluate.

Candidate diff (try-fix-2)
diff --git a/src/Controls/src/Core/Platform/GestureManager/GestureManager.cs b/src/Controls/src/Core/Platform/GestureManager/GestureManager.cs
index 9819c8133b..352f2be8f7 100644
--- a/src/Controls/src/Core/Platform/GestureManager/GestureManager.cs
+++ b/src/Controls/src/Core/Platform/GestureManager/GestureManager.cs
@@ -76,11 +76,7 @@ namespace Microsoft.Maui.Controls.Platform
 			if (GesturePlatformManager != null)
 				return;
 
-			var gesturePlatformManagerProvider = handler as IGesturePlatformManagerProvider;
-			GesturePlatformManager = gesturePlatformManagerProvider is null
-				? new GesturePlatformManager(handler)
-				: gesturePlatformManagerProvider.CreateGesturePlatformManager()
-					?? throw new InvalidOperationException($"{nameof(IGesturePlatformManagerProvider)}.{nameof(IGesturePlatformManagerProvider.CreateGesturePlatformManager)} cannot return null.");
+			GesturePlatformManager = GesturePlatformManagerResolver.Create(handler);
 
 			_handler = handler;
 			_containerView = handler.ContainerView;
diff --git a/src/Controls/src/Core/Platform/GestureManager/GesturePlatformManagerResolver.cs b/src/Controls/src/Core/Platform/GestureManager/GesturePlatformManagerResolver.cs
new file mode 100644
index 0000000000..5293540c6c
--- /dev/null
+++ b/src/Controls/src/Core/Platform/GestureManager/GesturePlatformManagerResolver.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Microsoft.Maui.Controls.Platform
+{
+	internal static class GesturePlatformManagerResolver
+	{
+		public static IGesturePlatformManager Create(IViewHandler handler)
+		{
+			if (handler is IGesturePlatformManagerProvider gesturePlatformManagerProvider)
+			{
+				return gesturePlatformManagerProvider.CreateGesturePlatformManager()
+					?? throw new InvalidOperationException($"{nameof(IGesturePlatformManagerProvider)}.{nameof(IGesturePlatformManagerProvider.CreateGesturePlatformManager)} cannot return null.");
+			}
+
+			return new GesturePlatformManager(handler);
+		}
+	}
+}

@MauiBot MauiBot removed the s/agent-review-in-progress AI review is currently running for this PR label Jun 11, 2026
@kubaflo kubaflo changed the base branch from main to net11.0 June 12, 2026 14:06
Copilot AI added 2 commits June 12, 2026 16:19
IGesturePlatformManager and IGesturePlatformManagerProvider were introduced
as internal in .NET 10 with TODOs to make them public in .NET 11. This branch
targets .NET 11, so promote both interfaces to public and record the new API
in PublicAPI.Unshipped.txt for every target framework.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…terface

Resolve PublicAPI.Unshipped.txt conflicts in all 7 target folders by keeping
both sides: net11.0's new API entries plus the public IGesturePlatformManager
and IGesturePlatformManagerProvider entries from this PR. Each file is net11.0's
version with exactly the three gesture entries inserted in sorted position.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@kubaflo

kubaflo commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 3 pipeline(s).

@kubaflo

kubaflo commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

AI code review refresh for net11.0 target

Head reviewed: b367ac200987d80f93a77947ac4fffeb40747265
Base: net11.0 · State: OPEN · Verdict:LGTM (pending CI)

Independent-first review: I read the diff, the full GestureManager.cs at head, the new interface files, the platform GesturePlatformManager.* declarations, the PublicAPI deltas, and the unit tests before the PR narrative.

What changed since the last (round-19) review

The prior MauiBot review was on 4810c80. The net11.0-relevant delta is commit e1bc48b3 "Make gesture platform manager interfaces public for .NET 11":

  • IGesturePlatformManager and IGesturePlatformManagerProvider are now public (were internal).
  • PublicAPI.Unshipped.txt updated consistently across all 7 target heads (net, net-android, net-ios, net-maccatalyst, net-tizen, net-windows, netstandard).

Promoting net11.0-only public API on a net11.0-targeted PR is the correct branch convention.

Prior-review reconciliation

  • Last MauiBot review = CHANGES_REQUESTED, but its code-review section recorded "No findings — lifecycle-safe and consistent with the PR narrative." The ❌ was a Gate failure flagged as base branch does not compile (test file references new API while the without-fix build reverts only sources) → classified infra/unreliable, not a code defect.
  • The one substantive open item from earlier rounds is a design-alignment question (linked issue described a Services-based replacement path; PR implements a handler-scoped provider). That is a Needs-discussion item for maintainers, not a correctness bug. The handler-scoped approach is lifecycle-consistent.

Findings (current head)

No blocking findings.

  • Null/default paths: handler as IGesturePlatformManagerProvider → falls back to the concrete GesturePlatformManager when the handler doesn't opt in; throws InvalidOperationException if a provider returns null. Both paths covered by tests. ✔
  • Lifecycle / leaks: DisconnectGestures() disposes and nulls the manager; SetupGestureManager() recreates on reconnect. Tests HandlerProvidedManagerIsDisposedOnDisconnect and HandlerProviderCreatesNewManagerAfterReconnect assert dispose-once + fresh creation. ✔
  • API design (minor, non-blocking): IGesturePlatformManager is an empty IDisposable marker — fine for the opt-in contract, but it exposes no members, so external consumers can only supply instances. Worth a maintainer sanity-check before it ships as net11.0 public API.
  • Collateral test tweaks (LayoutTests GetService narrowed to typeof(ILayoutManagerFactory), BOM removed from AnimationReadyHandler.cs) are harmless.

Blast radius

GestureManager is on the gesture hot-path for every gesture-bearing view on all platforms. Runtime behavior is unchanged today: no in-repo handler implements IGesturePlatformManagerProvider, so the new branch always falls through to new GesturePlatformManager(handler). The property type widened from the concrete type to the interface; no call site outside tests depends on concrete members. Low risk.

CI status

maui-pr, maui-pr-devicetests, maui-pr-uitests — all pending (re-queued via /azp run at 2026-06-12T19:18Z). No conclusive signal yet; verdict is contingent on these going green.

Confidence: High on code correctness/lifecycle; Medium overall pending CI completion and the maintainer design-alignment decision.


Non-approval disclaimer: this is an automated AI review refresh for informational purposes only. It is not an approval and does not request changes. A human maintainer must make the merge decision.

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

Labels

external-tfm 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.

Create IGesturePlatformManager so users can replace the behavior of our GesturePlatformManager a

5 participants