Skip to content
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

Synthesize remove events on PointerChange.ACTION_UP and PointerChange.ACTION_POINTER_UP #55157

Merged
merged 23 commits into from
Sep 14, 2024

Conversation

gmackall
Copy link
Member

@gmackall gmackall commented Sep 12, 2024

... when the input device type is touch.

Fixes (partially) flutter/flutter#154842 for touch events. Does not fix when using a stylus, that case will require a follow up PR.

Without fix:

wofix.mp4

With fix:

wfix.mp4

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the Flutter Style Guide and the C++, Objective-C, Java style guides.
  • I listed at least one issue that this PR fixes in the description above.
  • I added new tests to check the change I am making or feature I am adding, or the PR is test-exempt. See testing the engine for instructions on writing and running engine tests.
  • I updated/added relevant documentation (doc comments with ///).
  • I signed the CLA.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@gmackall gmackall marked this pull request as ready for review September 12, 2024 22:33
@gmackall
Copy link
Member Author

@moffatman Added you as a reviewer based on git history/github suggestion, feel free to remove if you think you aren't the right person.

@moffatman
Copy link
Contributor

won't this break android external mouse? when you click, it will remove the mouse pointer that is being used for hover? the approach doesn't seem right...

@gmackall
Copy link
Member Author

won't this break android external mouse? when you click, it will remove the mouse pointer that is being used for hover? the approach doesn't seem right...

I can find an external mouse to test, but I suspect it won't because we synthesize add events when the pointer is missing in most places.

It didn't break hovering with a mouse when mirroring my phone to AS, but I'm not sure how similarly that behaves to an actual external mouse.

@gmackall
Copy link
Member Author

I can also change to only synthesize remove events when the device is one of { PointerDeviceKind.TOUCH, PointerDeviceKind.STYLUS, PointerDeviceKind.INVERTED_STYLUS} , if you prefer.

@moffatman
Copy link
Contributor

Yep that sounds good for touch I agree no need to keep the pointer around

@gmackall
Copy link
Member Author

Yep that sounds good for touch I agree no need to keep the pointer around

Updated to only remove if the input device is one of { PointerDeviceKind.TOUCH, PointerDeviceKind.STYLUS, PointerDeviceKind.INVERTED_STYLUS }

@dkwingsmt
Copy link
Contributor

I think this change makes sense, since for a touch screen, once the pointer becomes up, the pointer can be considered removed. But why do you include styli as well? Many styli allow hovering (by literally hovering the stylus slightly above the screen).

@gmackall
Copy link
Member Author

I think this change makes sense, since for a touch screen, once the pointer becomes up, the pointer can be considered removed. But why do you include styli as well? Many styli allow hovering (by literally hovering the stylus slightly above the screen).

Mentioned in another chat but this was due to me not knowing that a stylus can hover, thanks for pointing it out! Changed to only remove for PointerDeviceKind.TOUCH.

@dkwingsmt
Copy link
Contributor

dkwingsmt commented Sep 13, 2024

Yeah I think while this PR definitely fixes the issue for touch screen, it doesn't for styli. As styli support hovering, I don't think we should remove hovering. However, they do suffer from the issue, since if the user puts away the stylus and then use the stylus to press a button, then the button receives a HOVER event and then a DOWN event, which opens and closes the menu back to back. We should think more carefully how to solve it for styli, but that can be left to another PR.

@gmackall
Copy link
Member Author

Yeah I think while this PR definitely fixes the issue for touch screen, it doesn't for styli. As styli support hovering, I don't think we should remove hovering. However, they do suffer from the issue, since if the user puts away the stylus and then use the stylus to press a button, then the button receives a HOVER event and then a DOWN event, which opens and closes the menu back to back. We should think more carefully how to solve it for styli, but that can be left to another PR.

Agreed, I'd be happy to discuss further on the fix for the stylus case

Copy link
Contributor

@dkwingsmt dkwingsmt left a comment

Choose a reason for hiding this comment

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

Mostly LGTM but I have a question as in the comments.

Comment on lines 184 to 187
// Flutter's pointer handling synthesizes an add event for each new pointer, but does not
// synthesize remove events. Remove each pointer on it's corresponding ACTION_UP or
// ACTION_POINTER_UP if and only if the input device is touch.
// See https://github.com/flutter/flutter/issues/154842.
Copy link
Contributor

Choose a reason for hiding this comment

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

I rewrote this part so that the motivation is more directly explained instead of sounding just like a patch to an issue. How do you think?

// Synthesizes remove events immediately after the UP event so that the touches 
// are divided into distinct segments, each beginning with a DOWN event and ending with an UP event. 
// This approach makes sense since each segment can be considered a separate pointer, 
// and it prevents Flutter from generating hover events between these segments, which are 
// not applicable to touch screens, as hovering is not possible.
// (Flutter will automatically synthesize an add event before the pointer makes its next contact.)

Copy link
Member Author

Choose a reason for hiding this comment

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

I think this is a better explanation - changed


int deviceType = getPointerDeviceTypeForToolType(event.getToolType(event.getActionIndex()));
boolean shouldRemovePointer =
updateForMultiplePointers && (deviceType == PointerDeviceKind.TOUCH);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you illustrate why the synthesis is only needed for updateForMultiplePointers?

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh I see, is it because updateForMultiplePointers is basically this-event-is-up?

Copy link
Member Author

@gmackall gmackall Sep 14, 2024

Choose a reason for hiding this comment

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

Longwinded ish answer: I think the naming makes it a little confusing, but my understanding is that if we take the definition of updateForMultiplePointers

boolean updateForMultiplePointers =
        !updateForSinglePointer
            && (maskedAction == MotionEvent.ACTION_UP
                || maskedAction == MotionEvent.ACTION_POINTER_UP);

which is equivalent to

boolean firstCondition = !(maskedAction == MotionEvent.ACTION_DOWN || maskedAction == MotionEvent.ACTION_POINTER_DOWN);
boolean secondCondition = (maskedAction == MotionEvent.ACTION_UP || maskedAction == MotionEvent.ACTION_POINTER_UP);
boolean updateForMultiplePointers = firstCondition && secondCondition;

If secondCondition is true, then firstCondition is also guaranteed to be true. And if secondCondition is false, then updateForMultiplePointers is going to be false, regardless of what firstCondition is.
So in reality updateForMultiplePointers is actually just

boolean updateForMultiplePointers = secondCondition;
// or
boolean updateForMultiplePointers = (maskedAction == MotionEvent.ACTION_UP || maskedAction == MotionEvent.ACTION_POINTER_UP);

Which is exactly the case we are looking to remove pointers for - on ACTION_UP and ACTION_POINTER_UP, aka when a finger leaves the screen.

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh I see, is it because updateForMultiplePointers is basically this-event-is-up?

Yeah this comment hadn't loaded for me when I wrote the longwinded answer above haha

Copy link
Contributor

@dkwingsmt dkwingsmt left a comment

Choose a reason for hiding this comment

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

LGTM

@dkwingsmt dkwingsmt added the autosubmit Merge PR when tree becomes green via auto submit App label Sep 14, 2024
@auto-submit auto-submit bot merged commit 4d8d851 into flutter:main Sep 14, 2024
30 checks passed
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Sep 14, 2024
auto-submit bot pushed a commit to flutter/flutter that referenced this pull request Sep 14, 2024
…155194)

flutter/engine@ab9daaa...4d8d851

2024-09-14 34871572+gmackall@users.noreply.github.com Synthesize remove events on `PointerChange.ACTION_UP` and `PointerChange.ACTION_POINTER_UP` (flutter/engine#55157)
2024-09-13 skia-flutter-autoroll@skia.org Roll Skia from bdc5e73cb6c9 to 2b8e33aa4824 (1 revision) (flutter/engine#55192)
2024-09-13 skia-flutter-autoroll@skia.org Roll Dart SDK from 302b6472b849 to c0f7e399ff4a (1 revision) (flutter/engine#55191)
2024-09-13 98614782+auto-submit[bot]@users.noreply.github.com Reverts "[skwasm] Scene builder optimizations for platform view placement (#54949)" (flutter/engine#55193)
2024-09-13 flar@google.com Delete VolatilePathTracker in favor of Dispatch tracking (flutter/engine#55125)
2024-09-13 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from 3YH1DEYJ-s93fHBw5... to -kKh_AYzPh_iEmTxK... (flutter/engine#55190)
2024-09-13 skia-flutter-autoroll@skia.org Roll Skia from 9877f459399a to bdc5e73cb6c9 (1 revision) (flutter/engine#55189)
2024-09-13 jonahwilliams@google.com [impeller] add Android flag for disabling surface control for debugging. (flutter/engine#55185)
2024-09-13 skia-flutter-autoroll@skia.org Roll Skia from a5a6d12b3642 to 9877f459399a (2 revisions) (flutter/engine#55187)
2024-09-13 skia-flutter-autoroll@skia.org Roll Dart SDK from eb664303c5ff to 302b6472b849 (2 revisions) (flutter/engine#55182)
2024-09-13 jacksongardner@google.com [skwasm] Scene builder optimizations for platform view placement (flutter/engine#54949)
2024-09-13 reidbaker@google.com add back test itSendsTextShowPasswordToFrameworkOnAttach with new mock for display metrics (flutter/engine#55110)

Also rolling transitive DEPS:
  fuchsia/sdk/core/linux-amd64 from 3YH1DEYJ-s93 to -kKh_AYzPh_i

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human
is aware of the problem.

To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
autosubmit Merge PR when tree becomes green via auto submit App platform-android
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants