Repository navigation
Conversation
…HCPP platform views
There was a problem hiding this comment.
Code Review
This pull request introduces an option unbufferOnMove to FlutterMutatorView to request unbuffered dispatch on Android ACTION_MOVE touch events, which is enabled in PlatformViewsController2. The review feedback suggests optimizing performance by tracking whether requestUnbufferedDispatch has already been called during the current gesture to avoid redundant JNI calls on every move event, and updating the tests to verify this behavior.
|
This pull request has been changed to a draft. The currently pending flutter-gold status will not be able to resolve until a new commit is pushed or the change is marked ready for review again. For more guidance, visit Writing a golden file test for Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
|
I'm going to close this, I think #192259 is the better approach |
…latformViewGestureRecognizer` rejects gesture (flutter#192259) Changes platform view touch input for all modes to request the unbuffered stream for the given event when the GestureArena determines the platform view has bowed out of ownership of that event, via [View.requestUnbufferedDispatch()](https://developer.android.com/reference/kotlin/android/view/View#requestunbuffereddispatch). Flutter content itself makes this request, but currently platform views don't. This greatly improves platform view scrolling smoothness, while having no breaking change or impact on platform views performing gesture handling (because the GestureArena has determined that they don't own the input event). ### Problem & Invariant Under high-load or scrolling scenarios, buffered touch dispatch causes visible jank and input lag. Flutter requests unbuffered dispatch for its own rendering, but platform views continue using buffered streams unless requested. Simply requesting unbuffered dispatch unconditionally can cause issues if gestures are still competing or owned by the platform view. Scoping unbuffered dispatch to gestures that Flutter has won ensures that platform views receive fast, unbuffered dispatch specifically during Flutter gestures (like scrolling). ### Architecture & Gesture Correlation (`embedderId`) Previous iterations attempted to correlate gestures across the channel by matching synthetic `downTime` timestamps packed into `PointerDownEvent.timeStamp`. However, resamplers or clock drift can alter event timestamps. Instead, this PR uses Flutter's canonical `embedderId` mechanism: 1. **Android Touch Processor**: When an Android `MotionEvent` arrives, `AndroidTouchProcessor` tracks it using `MotionEventTracker.track(event)` and populates `packet.putLong(motionEventId)`, which the framework receives as `PointerEvent.embedderId`. 2. **Framework Arena Resolution**: `_PlatformViewGestureRecognizer` records the `embedderId` of the pointer-down event. When Flutter wins the arena and calls `rejectGesture(pointer)`, the framework sends `gestureId` (set to `embedderId`) over the `flutter/platform_views` system channel. 3. **Engine Correlation (`MotionEventTracker.peek`)**: - `PlatformViewsController` and `PlatformViewsController2` handle `onRejectGesture(viewId, gestureId)`. - The controllers query `motionEventTracker.peek(MotionEventId.from(gestureId))` to look up the native `MotionEvent` without consuming it from the tracker. - From this `MotionEvent`, the native `downTime` is retrieved and passed to `FlutterMutatorView` and `PlatformViewWrapper`. - `PlatformViewGestureTracker` marks `flutterWonGesture = true` if the `downTime` matches the current active gesture stream, and keeps calling `requestUnbufferedDispatch()` for all remaining events in the gesture until `ACTION_UP` or `ACTION_CANCEL`. 4. **Graceful Degradation / Fails Closed**: - If `peek()` returns `null` (e.g. if the event was already popped or on non-Android embedders), or if `gestureId` is 0 or unmatched, the optimization degrades gracefully to standard buffered touch dispatch without breaking input handling. ### Tests - **Framework tests**: `packages/flutter/test/rendering/platform_view_test.dart` - Verifies `rejectGesture` passes the pointer's `embedderId` as `gestureId`. - Verifies multi-touch gestures correctly pass individual `embedderId`s. - Verifies no channel call is dispatched when `embedderId` is 0. - **Engine Robolectric tests**: - `PlatformViewsControllerTest`: Verifies `rejectGesture` with valid `gestureId` looks up tracked `MotionEvent` and enables unbuffered dispatch; verifies mismatched or missing IDs do not enable it. - `PlatformViewsController2Test`: Verifies same behavior on the modern hybrid composition pipeline. - `FlutterMutatorViewTest` and `PlatformViewWrapperTest`: Verifies gesture tracking across `ACTION_DOWN`, `ACTION_MOVE` sequences, and resetting on `ACTION_UP`/`ACTION_CANCEL`. Supersedes flutter#192249 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant in-code documentation (doc comments with `///`). - [x] If this PR introduces a new feature or capability, I created and linked a website documentation issue or PR in [flutter/website] (or verified none is needed). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [AI contribution guidelines]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [flutter/website]: https://github.com/flutter/website [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --- *Generated with Gemini / AI assistance.*
It makes scrolling a lot smoother 👍
AI pr description below
Description
When scrolling a Flutter scrollable by dragging across an embedded platform view, the mutator view was not calling
requestUnbufferedDispatch(event)(unlikeFlutterView, which calls it on every touch). As a result, Android's input pipeline kept the touch stream batched to VSYNC (typically 60Hz), making scrolling over platform views feel noticeably less smooth or lower-FPS compared to scrolling over regular Flutter content.This PR adds support to request unbuffered dispatch on
MotionEvent.ACTION_MOVEfor HCPP platform views:unbufferOnMoveonFlutterMutatorView, which defaults tofalseand is explicitly enabled inPlatformViewsController2(HCPP). Legacy Hybrid Composition (PlatformViewsController) and Texture Layer (PlatformViewWrapper) remain completely untouched to avoid breaking changes for existing modes.MotionEvent.ACTION_MOVEensures that stationary taps never request unbuffered delivery, protecting native tap recognizers from capacitive digitizer micro-jitter.Tests
FlutterMutatorViewTest.javaverifying unbuffered dispatch is requested onACTION_MOVEwhenunbufferOnMoveis enabled, and not onACTION_DOWNorACTION_UPor when disabled.PlatformViewsController2Test.javaandPlatformViewsControllerTest.javaverifying that HCPP enablesunbufferOnMoveand legacy Hybrid Composition keeps it disabled.Generated with Gemini / AI assistance.