Fix selection handles triggering Android system back gesture near screen edges#187723
Fix selection handles triggering Android system back gesture near screen edges#187723HibaChamkhi wants to merge 3 commits into
Conversation
…een edges
When text selection handles are positioned near the left or right screen
edges on Android with gesture navigation enabled, dragging the handle
could trigger the system back gesture instead of continuing the drag.
Fix this by calling View.setSystemGestureExclusionRects() via the platform
channel whenever selection handles are shown, updated, or hidden. This
tells Android to not intercept gestures in the handle areas.
Fixes: flutter#187647
There was a problem hiding this comment.
Code Review
This pull request introduces the _updateSystemGestureExclusionRects method in SelectionOverlay to update Android system gesture exclusion rects when text selection handles are shown, hidden, or updated, preventing system back gestures from intercepting handle drags. It also adds a corresponding widget test to verify this behavior on Android. Feedback suggests replacing the deprecated WidgetsBinding.instance.window with View.of(context) and adding a context.mounted check to prevent potential runtime exceptions.
| final renderBox = context.findRenderObject() as RenderBox?; | ||
| if (renderBox == null) { | ||
| return; | ||
| } | ||
| final rects = <Map<String, int>>[]; | ||
| for (final TextSelectionPoint endpoint in _selectionEndpoints) { | ||
| final Offset global = renderBox.localToGlobal(endpoint.point); | ||
| final double dpr = WidgetsBinding.instance.window.devicePixelRatio; | ||
| const handleWidth = 20.0; | ||
| const handleHeight = 20.0; | ||
| rects.add(<String, int>{ | ||
| 'left': ((global.dx - handleWidth) * dpr).round(), | ||
| 'top': (global.dy * dpr).round(), | ||
| 'right': ((global.dx + handleWidth) * dpr).round(), | ||
| 'bottom': ((global.dy + handleHeight) * dpr).round(), | ||
| }); | ||
| } |
There was a problem hiding this comment.
Using WidgetsBinding.instance.window is deprecated in Flutter. Instead, use View.of(context) to retrieve the devicePixelRatio associated with the current context.
Additionally, it is safer to check context.mounted before calling context.findRenderObject() or View.of(context) to prevent potential runtime exceptions if the widget is unmounted during updates.
if (!context.mounted) {
return;
}
final renderBox = context.findRenderObject() as RenderBox?;
if (renderBox == null) {
return;
}
final rects = <Map<String, int>>[];
final double dpr = View.of(context).devicePixelRatio;
for (final TextSelectionPoint endpoint in _selectionEndpoints) {
final Offset global = renderBox.localToGlobal(endpoint.point);
const handleWidth = 20.0;
const handleHeight = 20.0;
rects.add(<String, int>{
'left': ((global.dx - handleWidth) * dpr).round(),
'top': (global.dy * dpr).round(),
'right': ((global.dx + handleWidth) * dpr).round(),
'bottom': ((global.dy + handleHeight) * dpr).round(),
});
}… add context.mounted check
When text selection handles are positioned near the left or right screen edges on Android with gesture navigation enabled, dragging a handle triggers the Android system back gesture instead of continuing the drag. This happens because Flutter never calls View.setSystemGestureExclusionRects() to exclude handle areas from system gesture detection, unlike native Android EditText which does this automatically.
This PR fixes the issue by calling View.setSystemGestureExclusionRects() via the platform channel whenever selection handles are shown, updated, or hidden in SelectionOverlay. The exclusion rects are cleared when handles are hidden.
The engine-side changes (PlatformChannel.java, PlatformPlugin.java) will follow in a separate flutter/engine PR.
Fixes #187647