Skip to content

Commit e041b1f

Browse files
RedthCopilot
andcommitted
Dispatch tap and pointer gestures through the new public MAUI APIs
dotnet/maui#37420 and #37671 made most of the gesture dispatch surface public. Measured by reflecting over the shipped assemblies rather than reading source: 11.0.0-preview.7.26418.3 Tap (none) Pointer (none) LongPress (none) 11.0.0-preview.7.26426.4 Tap SendTapped Pointer SendPointerEntered/Exited/Moved/Pressed/Released LongPress (none) So the package pin moves from 26418.3 to 26426.4 (nuspec commit bedd1b18b7). All seven MAUI packages were confirmed present at that stamp before bumping, and the pin is kept in sync in eng/baselines.json as that file requires. Tap and pointer now dispatch for real. Long press is the only gesture this backend can detect but not raise: SendLongPressed and SendLongPressing are still internal, with no ILongPressGestureController alternative. That is now stated as exactly two named members rather than a blanket "tap, long-press and pointer are blocked". Drag and drop also changed reason. Their dispatch members are public as of 26426.4, so they are no longer dispatch-blocked - they remain unsupported purely because NUI has no view-level drag/drop that maps onto the per-view recognizer semantics. The matrix now says so. Position resolution ------------------- The new members take Func<IElement?, Point?> rather than a point, so MAUI can ask for a position relative to an arbitrary element. The Tizen detectors report a view-local position, which is returned for the view itself and for the null request. For any other element the resolver returns null - MAUI's own encoding of "cannot be determined" - because translating between two elements needs both on-screen origins, which requires a native call per element that the Tizen platform layer does not expose here. A plausible-looking wrong coordinate would be worse. PlatformPointerEventArgs is left null and ButtonsMask at its default. Both are optional, and NUI reports neither for touch and hover, so fabricating them would mislead. Testing ------- 158 tests, up from 150. The dispatcher tests use real recognizers, so they prove the public path delivers events rather than merely compiling; verified by stubbing the SendTapped call out and watching three tests fail. LongPressSendMembersAreStillInternalUpstream asserts by reflection that the two named members are absent from BindingFlags.Public and present under NonPublic, so the support matrix's central claim cannot rot. It fails when upstream opens the API. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent 1d82a84 commit e041b1f

5 files changed

Lines changed: 264 additions & 111 deletions

File tree

Directory.Packages.props

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,22 @@
1212

1313
<ItemGroup Label="MAUI (neutral assemblies consumed from the published feed)">
1414
<!--
15-
Pinned to eng/baselines.json > developmentPackageBaseline: the first coherent
16-
public-feed net11 MAUI package set, whose nuspec repository commits all resolve to
17-
0b3bb76d2d (PR #36657). Bumping this without regenerating the API baselines will
18-
produce misleading diffs.
15+
Pinned to eng/baselines.json > developmentPackageBaseline. Bumping this without
16+
regenerating the API baselines will produce misleading diffs.
17+
18+
Moved from 26418.3 (nuspec commit 0b3bb76d2d) to 26426.4 (nuspec commit bedd1b18b7)
19+
to pick up the public gesture dispatch APIs from dotnet/maui#37420 and #37671.
20+
26418.3 predates both merges, so TapGestureRecognizer.SendTapped and the
21+
PointerGestureRecognizer send members are internal there and an out-of-tree backend
22+
cannot raise those gestures at all. Verified by reflecting over both packages.
1923
-->
20-
<PackageVersion Include="Microsoft.Maui.Core" Version="11.0.0-preview.7.26418.3" />
21-
<PackageVersion Include="Microsoft.Maui.Controls" Version="11.0.0-preview.7.26418.3" />
22-
<PackageVersion Include="Microsoft.Maui.Controls.Core" Version="11.0.0-preview.7.26418.3" />
23-
<PackageVersion Include="Microsoft.Maui.Essentials" Version="11.0.0-preview.7.26418.3" />
24-
<PackageVersion Include="Microsoft.Maui.Graphics" Version="11.0.0-preview.7.26418.3" />
25-
<PackageVersion Include="Microsoft.Maui.Maps" Version="11.0.0-preview.7.26418.3" />
26-
<PackageVersion Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="11.0.0-preview.7.26418.3" />
24+
<PackageVersion Include="Microsoft.Maui.Core" Version="11.0.0-preview.7.26426.4" />
25+
<PackageVersion Include="Microsoft.Maui.Controls" Version="11.0.0-preview.7.26426.4" />
26+
<PackageVersion Include="Microsoft.Maui.Controls.Core" Version="11.0.0-preview.7.26426.4" />
27+
<PackageVersion Include="Microsoft.Maui.Essentials" Version="11.0.0-preview.7.26426.4" />
28+
<PackageVersion Include="Microsoft.Maui.Graphics" Version="11.0.0-preview.7.26426.4" />
29+
<PackageVersion Include="Microsoft.Maui.Maps" Version="11.0.0-preview.7.26426.4" />
30+
<PackageVersion Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="11.0.0-preview.7.26426.4" />
2731
</ItemGroup>
2832

2933
<ItemGroup Label="ASP.NET Core (BlazorWebView dependencies)">
@@ -32,11 +36,11 @@
3236
3337
These are ASP.NET Core packages, not MAUI packages, and they do not share MAUI's
3438
version stamp. There is no Microsoft.AspNetCore.Components.WebView at
35-
11.0.0-preview.7.26418.3 - that version simply does not exist - and pinning it there
39+
11.0.0-preview.7.26426.4 - that version simply does not exist - and pinning it there
3640
produced NU1102 for the whole BlazorWebView graph.
3741
3842
11.0.0-preview.7.26381.103 is not a guess: it is what
39-
Microsoft.AspNetCore.Components.WebView.Maui 11.0.0-preview.7.26418.3 declares in its
43+
Microsoft.AspNetCore.Components.WebView.Maui 11.0.0-preview.7.26426.4 declares in its
4044
own nuspec, and it matches the SDK build we pin in global.json
4145
(11.0.100-preview.7.26381.103), so the whole graph stays on one ASP.NET Core build.
4246

docs/tizen-gesture-support-matrix.md

Lines changed: 74 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -15,67 +15,88 @@ out-of-tree backend: it uses only public .NET MAUI API and does not use `Dispatc
1515

1616
## Summary
1717

18+
Measured against **MAUI 11.0.0-preview.7.26426.4**, which contains
19+
[dotnet/maui#37420](https://github.com/dotnet/maui/pull/37420) and
20+
[#37671](https://github.com/dotnet/maui/pull/37671).
21+
1822
| Recognizer | Detection (NUI) | Dispatch (public MAUI API) | End to end |
1923
|---|---|---|---|
2024
| `PanGestureRecognizer` | `PanGestureDetector` | `IPanGestureController` | ✅ Works |
2125
| `PinchGestureRecognizer` | `PinchGestureDetector` | `IPinchGestureController` | ✅ Works |
2226
| `SwipeGestureRecognizer` | `PanGestureDetector` | `ISwipeGestureController` | ✅ Works |
23-
| `TapGestureRecognizer` | `TapGestureDetector` | `SendTapped` is internal | ⚠️ Blocked on MAUI |
24-
| `LongPressGestureRecognizer` | `LongPressGestureDetector` |`SendLongPressing` / `SendLongPressed` are internal | ⚠️ Blocked on MAUI |
25-
| `PointerGestureRecognizer` | `View.TouchEvent` + `View.HoverEvent` |all send members internal | ⚠️ Blocked on MAUI |
26-
| `DragGestureRecognizer` | ❌ no view-level NUI equivalent | `SendDragStarting` is internal | ❌ Not supported |
27-
| `DropGestureRecognizer` | ❌ no view-level NUI equivalent | ⚠️ only `SendDragOver` is public | ❌ Not supported |
27+
| `TapGestureRecognizer` | `TapGestureDetector` | `SendTapped` | ✅ Works |
28+
| `PointerGestureRecognizer` | `View.TouchEvent` + `View.HoverEvent` | `SendPointerEntered` / `Exited` / `Moved` / `Pressed` / `Released` | ✅ Works |
29+
| `LongPressGestureRecognizer` | `LongPressGestureDetector` |`SendLongPressed` / `SendLongPressing` still internal | ⚠️ Blocked on MAUI |
30+
| `DragGestureRecognizer` | ❌ no view-level NUI equivalent | `SendDragStarting` / `SendDropCompleted` | ❌ Not supported (detection) |
31+
| `DropGestureRecognizer` | ❌ no view-level NUI equivalent | `SendDragOver` / `SendDragLeave` / `SendDrop` | ❌ Not supported (detection) |
2832

2933
Legend: ✅ works today · ⚠️ implemented and tested up to the blocking seam · ❌ not supported.
3034

35+
Note the change in *why* drag and drop are unsupported. Their dispatch members are public as of
36+
26426.4; what is missing is detection. See [Drag and drop](#drag-and-drop).
37+
3138
---
3239

33-
## The dispatch gap
40+
## The remaining dispatch gap
3441

35-
.NET MAUI 11 exposes exactly three public gesture controller interfaces:
42+
Most of this gap has closed. MAUI 11.0.0-preview.7.26426.4 makes the tap, pointer and
43+
drag/drop dispatch members public, on top of the three controller interfaces that were
44+
already public:
3645

3746
```text
38-
Microsoft.Maui.Controls.IPanGestureController
39-
Microsoft.Maui.Controls.IPinchGestureController
40-
Microsoft.Maui.Controls.ISwipeGestureController
47+
Microsoft.Maui.Controls.IPanGestureController (already public)
48+
Microsoft.Maui.Controls.IPinchGestureController (already public)
49+
Microsoft.Maui.Controls.ISwipeGestureController (already public)
50+
TapGestureRecognizer.SendTapped (new in #37420 / #37671)
51+
PointerGestureRecognizer.SendPointerEntered/Exited/… (new in #37420 / #37671)
52+
DragGestureRecognizer.SendDragStarting/SendDropCompleted (new in #37420 / #37671)
53+
DropGestureRecognizer.SendDragOver/SendDragLeave/SendDrop(new in #37420 / #37671)
4154
```
4255

43-
There is no `ITapGestureController`, no `ILongPressGestureController`, and no pointer
44-
equivalent. `TapGestureRecognizer`, `LongPressGestureRecognizer` and
45-
`PointerGestureRecognizer` expose no public `Send*` members at all — verified by reflecting
46-
over the shipped `Microsoft.Maui.Controls` assembly, not by reading source.
56+
**Exactly two members are still internal**, and they are the only reason any ⚠️ row remains:
4757

48-
This is a **true public API gap**, not a limitation of Tizen. The same gap blocks any
49-
out-of-tree backend from supporting these gestures.
58+
```text
59+
LongPressGestureRecognizer.SendLongPressed(View sender, Func<IElement?, Point?> getPosition)
60+
LongPressGestureRecognizer.SendLongPressing(View sender, GestureStatus status, Func<IElement?, Point?> getPosition)
61+
```
62+
63+
Both were verified by reflecting over the shipped 26426.4 assembly, not by reading source:
64+
they are absent from `BindingFlags.Public` and present under `BindingFlags.NonPublic`. There is
65+
no `ILongPressGestureController` either. `TizenGestureDispatcherTests` in this repository
66+
asserts precisely that, so the claim cannot silently rot.
5067

5168
### How it is handled here
5269

53-
Detection is implemented in full. Dispatch goes through one seam,
70+
Detection is implemented in full for every gesture. Dispatch goes through one seam,
5471
`ITizenGestureDispatcher`:
5572

56-
- `TizenGestureDispatcher` raises pan, pinch and swipe through the public controllers.
57-
- For tap, long press and pointer it logs once per gesture kind and returns. It never
58-
throws, so a view carrying a `TapGestureRecognizer` behaves exactly as if it had no
59-
gesture rather than crashing.
73+
- `TizenGestureDispatcher` raises pan, pinch and swipe through the public controllers, and tap
74+
and pointer through their public send members.
75+
- For long press it logs once and returns. It never throws, so a view carrying a
76+
`LongPressGestureRecognizer` behaves exactly as if it had no gesture rather than crashing.
6077
- `ITizenGestureDispatcher.IsSupported(TizenGestureKind)` reports the matrix above.
6178

62-
`TizenGestureDispatcherTests` pins this reality: `TapCannotBeRaisedBecauseMauiKeepsTheApiInternal`
63-
and its siblings assert that the recognizer's event does **not** fire. When the upstream
64-
API lands, those tests fail loudly and the only change needed is to complete
65-
`TizenGestureDispatcher` — no handler, detector or lifecycle code has to move.
79+
`LongPressCannotBeRaisedBecauseMauiKeepsTheApiInternal` asserts the recognizer's events do
80+
**not** fire, and `LongPressSendMembersAreStillInternalUpstream` asserts the two members are
81+
still non-public. Both fail once upstream opens the API, and the only change needed is to
82+
complete `TizenGestureDispatcher` — no handler, detector or lifecycle code has to move.
83+
84+
### Position resolution
6685

67-
### What upstream needs to change
86+
The new tap and pointer members take a `Func<IElement?, Point?> getPosition` rather than a
87+
plain point, so MAUI can ask for the position relative to an arbitrary element.
6888

69-
Any one of these would unblock the ⚠️ rows:
89+
The Tizen detectors report a position local to the view the gesture occurred on. That value is
90+
returned for the view itself and for the `null` (view-relative) request. For any *other* element
91+
the resolver returns `null`, which is how MAUI models "cannot be determined": translating between
92+
two elements needs both on-screen origins, which requires a native call per element that the
93+
Tizen platform layer does not expose to this assembly. Returning a plausible-looking but wrong
94+
coordinate would be worse, so it is not done.
7095

71-
1. Make the existing `SendTapped` / `SendLongPressing` / `SendLongPressed` and pointer send
72-
members public, mirroring what was already done for pan, pinch and swipe; or
73-
2. add `ITapGestureController`, `ILongPressGestureController` and `IPointerGestureController`
74-
public interfaces alongside the existing three.
96+
### What upstream still needs to change
7597

76-
Option 2 is more consistent with how pan, pinch and swipe are already exposed, and was the
77-
shape used by [dotnet/maui#36655](https://github.com/dotnet/maui/pull/36655) when it made
78-
`IGesturePlatformManager` and `IGesturePlatformManagerFactory` public.
98+
Making `SendLongPressed` and `SendLongPressing` public — exactly as #37420 did for tap and
99+
pointer — is sufficient. No new interface is required.
79100

80101
---
81102

@@ -108,9 +129,9 @@ the origin rather than producing `NaN`.
108129

109130
### Tap
110131

111-
`TapGestureGesture.NumberOfTaps` is compared against
112-
`TapGestureRecognizer.NumberOfTapsRequired` and non-matching counts are ignored, matching
113-
the original backend. Dispatch is blocked (see above).
132+
`TapGesture.NumberOfTaps` is compared against `TapGestureRecognizer.NumberOfTapsRequired` and
133+
non-matching counts are ignored, matching the original backend. Dispatched through the public
134+
`SendTapped`.
114135

115136
### Long press
116137

@@ -142,7 +163,12 @@ mapping `PointStateType` onto pointer transitions:
142163
| Hover | `Motion` | `Moved` |
143164
| Hover | `Finished`, `Leave` | `Exited` |
144165

145-
Events are never consumed, so the view's own handlers still run. Dispatch is blocked.
166+
Events are never consumed, so the view's own handlers still run. Each transition is dispatched
167+
through its matching public send member.
168+
169+
`PlatformPointerEventArgs` is left `null` and `ButtonsMask` at its default. Both parameters are
170+
optional; NUI reports neither a platform-native pointer event object nor a button mask for touch
171+
and hover, so supplying a fabricated value would be misleading.
146172

147173
### Drag and drop
148174

@@ -152,8 +178,9 @@ Not supported, for two reasons:
152178
explicit `Tizen.NUI.DragAndDrop` session started by the application. It does not map onto
153179
.NET MAUI's per-view `DragGestureRecognizer` / `DropGestureRecognizer` semantics, which
154180
expect the platform to originate a drag from a view based on its recognizer configuration.
155-
- **Dispatch.** `DropGestureRecognizer` only exposes `SendDragOver` publicly. The members
156-
needed to complete a drop, and everything needed to start a drag, are internal.
181+
- **Dispatch.** No longer the blocker: `SendDragStarting`, `SendDropCompleted`, `SendDragOver`,
182+
`SendDragLeave` and `SendDrop` are all public as of 26426.4. Drag and drop remain unsupported
183+
purely because there is nothing on the Tizen side to drive them.
157184

158185
`TizenGestureHandlerFactory` returns `null` for both recognizer types, so they are skipped
159186
rather than throwing. `DragAndDropRecognizersAreNotSupported` covers this.
@@ -166,14 +193,15 @@ The gesture stack is NUI-based and profile-independent: `TapGestureDetector`,
166193
`PanGestureDetector`, `PinchGestureDetector` and `LongPressGestureDetector` are part of core
167194
TizenFX and are present on every profile.
168195

169-
| Profile | Pan | Pinch | Swipe | Tap (det.) | Long press (det.) | Pointer (det.) | Drag/drop |
196+
| Profile | Pan | Pinch | Swipe | Tap | Pointer | Long press (det.) | Drag/drop |
170197
|---|---|---|---|---|---|---|---|
171198
| Mobile ||||||||
172-
| Wearable || ⚠️ ||| | ⚠️ ||
173-
| TV ||||| | ⚠️ ||
174-
| IoT / headed || ⚠️ ||| | ⚠️ ||
199+
| Wearable || ⚠️ ||| ⚠️ | ||
200+
| TV ||||| ⚠️ | ||
201+
| IoT / headed || ⚠️ ||| ⚠️ | ||
175202

176-
"det." means detection only; dispatch is still gated on the MAUI API gap above.
203+
Long press is marked "det." because detection works on every profile but dispatch is still gated
204+
on the two internal members above. Every other ✅ is end to end.
177205

178206
Profile caveats:
179207

@@ -200,7 +228,7 @@ factory can therefore refine this table without changing any other code.
200228
|---|---|
201229
| Gesture translation (totals, scaling, gesture identity, tap counts, pointer mapping) | `tests/Controls.UnitTests/TizenGestureTranslationTests.cs` |
202230
| Manager and detector lifecycle (attach, detach, enable, dispose, collection changes) | `tests/Controls.UnitTests/TizenGesturePlatformManagerTests.cs` |
203-
| Dispatch through real MAUI recognizers, and the blocked gestures | `tests/Controls.UnitTests/TizenGestureDispatcherTests.cs` |
231+
| Dispatch through real MAUI recognizers, position resolution, and the one blocked gesture | `tests/Controls.UnitTests/TizenGestureDispatcherTests.cs` |
204232
| DI registration and lifetimes | `tests/Controls.UnitTests/TizenServiceRegistrationTests.cs` |
205233
| NUI adapters under `Core/Platform/Nui` | Type-checked against `Samsung.Tizen.Ref.API15` and `Tizen.UIExtensions.NUI` 0.9.2 by `tests/Maui.Tizen.Controls.RefPackCompile`; behaviour needs a device |
206234

eng/baselines.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,11 @@
5757
"note": "This is the ONLY ref that still carries src/Compatibility Tizen sources (70 files). They were deleted upstream on net11.0, so a net11.0-only baseline loses them silently."
5858
},
5959
"developmentPackageBaseline": {
60-
"version": "11.0.0-preview.7.26418.3",
60+
"version": "11.0.0-preview.7.26426.4",
6161
"feed": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet11/nuget/v3/index.json",
62-
"nuspecRepositoryCommit": "0b3bb76d2dd68d76b7c1302f43a76270d5949564",
63-
"role": "First coherent public-feed MAUI package set for net11. Used when building against published MAUI packages rather than source."
62+
"nuspecRepositoryCommit": "bedd1b18b7682193e05b47267509cec8c49c6853",
63+
"role": "Public-feed MAUI package set for net11. Used when building against published MAUI packages rather than source.",
64+
"note": "Moved from 11.0.0-preview.7.26418.3 (nuspec commit 0b3bb76d2d) to pick up the public gesture dispatch APIs from dotnet/maui#37420 and #37671. 26418.3 predates both merges, so TapGestureRecognizer.SendTapped and the PointerGestureRecognizer send members are internal there. LongPressGestureRecognizer.SendLongPressed/SendLongPressing remain internal even in 26426.4."
6465
},
6566
"provenancePullRequests": [
6667
{ "number": 2360, "title": "Adds Tizen backend", "upstreamCommit": "438aef2e5d" },

0 commit comments

Comments
 (0)