-
Notifications
You must be signed in to change notification settings - Fork 29.7k
fix: gesture blocked in android webview after zoom #177572
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: gesture blocked in android webview after zoom #177572
Conversation
letrungdo
commented
Oct 27, 2025
- Fix issue [Android] button actions in webview_flutter are blocked #169486
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request addresses an issue where touch gestures on Android platform views fail after transformations like zooming. The approach of reconstructing the MotionEvent with transformed coordinates from Flutter is sound and effectively solves the problem. The new tests for single and multi-touch scenarios are thorough and validate the fix. However, I've identified a potential regression where the action from the PlatformViewTouch is used instead of the original MotionEvent's action, which could affect gesture recognition. I've provided a suggestion to align with the existing behavior.
...e/src/flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java
Show resolved
Hide resolved
7d28b17 to
d992597
Compare
|
An existing Git SHA, To re-trigger presubmits after closing or re-opeing a PR, or pushing a HEAD commit (i.e. with |
d992597 to
a956ca8
Compare
|
An existing Git SHA, To re-trigger presubmits after closing or re-opeing a PR, or pushing a HEAD commit (i.e. with |
gmackall
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for taking the time to put together this contribution. Unfortunately we cannot accept a change which regresses the verification status of these input events.
You can read more about verification of input events here. |
| // We need to use Flutter's calculated coordinates which may include complex transformations | ||
| // (zoom, scale, rotation) that can't be represented by simple offsetLocation(). | ||
| // Creating a new MotionEvent with the correct coordinates ensures gestures work properly | ||
| // after transformations like zoom, but loses the verifiable input flag. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the record, I think this is not a correct description of the mechanism by which this change fixes the problem. If we print out coordinates for a given pointer, for both the original translated event and new constructed event (i.e. the event below), you will see the coordinates are identical.
Rather, the problem is that the SingleTouchContainer you added is pruning input events, leading to a different pointer count between the two MotionEvents, as we can see if we print out some of the contents of these two events:
E/HI GRAY,( 8361): tracking a new motion event: io.flutter.embedding.android.MotionEventTracker$MotionEventId@94abf41
E/HI GRAY ( 8361): original event info:
E/HI GRAY ( 8361): pointer count is: 2
E/HI GRAY ( 8361): event action is: 2
-------------- LOOPING OVER POINTER COUNT --------------
E/HI GRAY ( 8361): pointer properties are: PointerProperties(id = 0, tooltype = 1, )
E/HI GRAY ( 8361): pointer coords are: (x=264.75,y=498.0) and size=0.0847811
E/HI GRAY ( 8361): point id is: 0
E/HI GRAY ( 8361): pointer properties are: PointerProperties(id = 1, tooltype = 1, )
E/HI GRAY ( 8361): pointer coords are: (x=392.25,y=1228.5) and size=0.09659486
E/HI GRAY ( 8361): point id is: 1
E/HI GRAY ( 8361): constructed event info:
E/HI GRAY ( 8361): pointer count is: 1
E/HI GRAY ( 8361): event action is: 2
-------------- LOOPING OVER POINTER COUNT --------------
E/HI GRAY ( 8361): pointer properties are: PointerProperties(id = 0, tooltype = 1, )
E/HI GRAY ( 8361): pointer coords are: (x=264.75,y=498.0) and size=0.0847811
E/HI GRAY ( 8361): point id is: 0
Unfortunately it does not seem there is an api that would allow us to modify the pointer count of the original event.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @gmackall for the clarification! You're right - the issue is pointer count mismatch, not coordinates.
Updated Fix
I've revised the implementation to preserve verifiable input whenever possible:
if (trackedEvent.getPointerCount() == touch.pointerCount) {
// Counts match → preserve verifiable flag
translateMotionEvent(trackedEvent, pointerCoords);
return trackedEvent;
}
// Counts mismatch → must reconstruct (loses verifiable flag)
return MotionEvent.obtain(...);This minimizes security impact by only sacrificing the verifiable flag when pointer counts actually mismatch (e.g., gesture recognizer filtering).
Why Accept This Trade-off?
No alternative: Android has no API to modify pointer count while preserving verifiability
Functional > theoretical security: App is completely unusable after zoom without this fix
Minimal scope: Only affects pointer count mismatch cases, not normal gestures
Already validated: Events passed through Flutter framework validation
Would this approach be acceptable given the Android platform constraint?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think the approach of preserving the verifiability when possible, but falling back when not possible, is a good solution here (it was also the approach I was going to suggest based on some offline discussions).
The original integration test for this behavior was regrettably reverted without ever being relanded #140836, #162895, so it would be easy to accidentally introduce a regression here where we are falling back in all cases to unverified events. But I think this approach is safe enough to land, in my opinion.
@reidbaker WDYT?
6c2bed6 to
9e7ebb0
Compare
...e/src/flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java
Outdated
Show resolved
Hide resolved
9e7ebb0 to
9fe2ca1
Compare
|
@gmackall Could you please re-run the failing checks? They appear to be flaky. Linux linux_web_engine_tests Failing after 33m |
|
Spoke with @reidbaker offline, going to land #177804 first and then we should be able to land this |
This was originally landed in #140836 but the pr did not hook it up to ci. It was then removed in #162895 First got the driver test running: `flutter drive -t lib/main.dart --driver test_driver/main_test.dart` from the directory of the test app then got the devicelab harness working via `../../bin/cache/dart-sdk/bin/dart bin/test_runner.dart test -t android_verified_input_test` from the `dev/devicelab` directory and then finally hooked up to ci with the configuration in the `.ci.yaml` Restoring in a passing state, in advance of landing #177572 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [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]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [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. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [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 [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 --------- Co-authored-by: Gray Mackall <[email protected]>
|
Sorry for the delay here, been having some trouble getting the integration test to run properly on our CI. I believe I have narrowed it down to a mismatch in ADB versions, so it should hopefully be fixed shortly by #178018 |
<!-- Thanks for filing a pull request! Reviewers are typically assigned within a week of filing a request. To learn more about code review, see our documentation on Tree Hygiene: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md --> - Fix issue flutter#169486 Co-authored-by: Gray Mackall <[email protected]>
<!-- Thanks for filing a pull request! Reviewers are typically assigned within a week of filing a request. To learn more about code review, see our documentation on Tree Hygiene: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md --> - Fix issue flutter#169486 Co-authored-by: Gray Mackall <[email protected]>
This was originally landed in flutter#140836 but the pr did not hook it up to ci. It was then removed in flutter#162895 First got the driver test running: `flutter drive -t lib/main.dart --driver test_driver/main_test.dart` from the directory of the test app then got the devicelab harness working via `../../bin/cache/dart-sdk/bin/dart bin/test_runner.dart test -t android_verified_input_test` from the `dev/devicelab` directory and then finally hooked up to ci with the configuration in the `.ci.yaml` Restoring in a passing state, in advance of landing flutter#177572 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [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]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [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. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [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 [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 --------- Co-authored-by: Gray Mackall <[email protected]>
<!-- Thanks for filing a pull request! Reviewers are typically assigned within a week of filing a request. To learn more about code review, see our documentation on Tree Hygiene: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md --> - Fix issue flutter#169486 Co-authored-by: Gray Mackall <[email protected]>