mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Propagate positions of secondary pointers in UP events on Android (#23797)
This commit is contained in:
parent
7245c4a6f6
commit
ba4cf054bd
@ -1 +1 @@
|
|||||||
88cb78cdf62ceb206e740853d3afd060bb8d781c
|
b5758d0d3848d8ed77308d97734b9a7933c3844f
|
||||||
|
@ -95,23 +95,6 @@ void diffPointerCoordsList(StringBuffer diffBuffer,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSinglePointerAction(originalEvent['action'])) {
|
|
||||||
final int idx = getPointerIdx(originalEvent['action']);
|
|
||||||
final Map<String, dynamic> expected =
|
|
||||||
expectedList[idx].cast<String, dynamic>();
|
|
||||||
final Map<String, dynamic> actual = actualList[idx].cast<String, dynamic>();
|
|
||||||
diffPointerCoords(expected, actual, idx, diffBuffer);
|
|
||||||
// For POINTER_UP and POINTER_DOWN events the engine drops the data for all pointers
|
|
||||||
// but for the pointer that was taken up/down.
|
|
||||||
// See: https://github.com/flutter/flutter/issues/19882
|
|
||||||
//
|
|
||||||
// Until that issue is resolved, we only compare the pointer for which the action
|
|
||||||
// applies to here.
|
|
||||||
//
|
|
||||||
// TODO(amirh): Compare all pointers once the issue mentioned above is resolved.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < expectedList.length; i++) {
|
for (int i = 0; i < expectedList.length; i++) {
|
||||||
final Map<String, dynamic> expected =
|
final Map<String, dynamic> expected =
|
||||||
expectedList[i].cast<String, dynamic>();
|
expectedList[i].cast<String, dynamic>();
|
||||||
@ -151,12 +134,6 @@ void diffMaps(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSinglePointerAction(int action) {
|
|
||||||
final int actionMasked = getActionMasked(action);
|
|
||||||
return actionMasked == 5 || // POINTER_DOWN
|
|
||||||
actionMasked == 6; // POINTER_UP
|
|
||||||
}
|
|
||||||
|
|
||||||
int getActionMasked(int action) => action & 0xff;
|
int getActionMasked(int action) => action & 0xff;
|
||||||
|
|
||||||
int getPointerIdx(int action) => (action >> 8) & 0xff;
|
int getPointerIdx(int action) => (action >> 8) & 0xff;
|
||||||
|
@ -239,7 +239,8 @@ class PointerEventConverter {
|
|||||||
radiusMin: radiusMin,
|
radiusMin: radiusMin,
|
||||||
radiusMax: radiusMax,
|
radiusMax: radiusMax,
|
||||||
orientation: datum.orientation,
|
orientation: datum.orientation,
|
||||||
tilt: datum.tilt
|
tilt: datum.tilt,
|
||||||
|
platformData: datum.platformData,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case ui.PointerChange.up:
|
case ui.PointerChange.up:
|
||||||
|
@ -115,6 +115,7 @@ abstract class PointerEvent {
|
|||||||
this.radiusMax = 0.0,
|
this.radiusMax = 0.0,
|
||||||
this.orientation = 0.0,
|
this.orientation = 0.0,
|
||||||
this.tilt = 0.0,
|
this.tilt = 0.0,
|
||||||
|
this.platformData = 0,
|
||||||
this.synthesized = false,
|
this.synthesized = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -245,6 +246,9 @@ abstract class PointerEvent {
|
|||||||
/// the stylus is flat on that surface).
|
/// the stylus is flat on that surface).
|
||||||
final double tilt;
|
final double tilt;
|
||||||
|
|
||||||
|
/// Opaque platform-specific data associated with the event.
|
||||||
|
final int platformData;
|
||||||
|
|
||||||
/// We occasionally synthesize PointerEvents that aren't exact translations
|
/// We occasionally synthesize PointerEvents that aren't exact translations
|
||||||
/// of [ui.PointerData] from the engine to cover small cross-OS discrepancies
|
/// of [ui.PointerData] from the engine to cover small cross-OS discrepancies
|
||||||
/// in pointer behaviors.
|
/// in pointer behaviors.
|
||||||
@ -285,6 +289,7 @@ abstract class PointerEvent {
|
|||||||
'radiusMax: $radiusMax, '
|
'radiusMax: $radiusMax, '
|
||||||
'orientation: $orientation, '
|
'orientation: $orientation, '
|
||||||
'tilt: $tilt, '
|
'tilt: $tilt, '
|
||||||
|
'platformData: $platformData, '
|
||||||
'synthesized: $synthesized'
|
'synthesized: $synthesized'
|
||||||
')';
|
')';
|
||||||
}
|
}
|
||||||
@ -495,6 +500,7 @@ class PointerMoveEvent extends PointerEvent {
|
|||||||
double radiusMax = 0.0,
|
double radiusMax = 0.0,
|
||||||
double orientation = 0.0,
|
double orientation = 0.0,
|
||||||
double tilt = 0.0,
|
double tilt = 0.0,
|
||||||
|
int platformData = 0,
|
||||||
bool synthesized = false,
|
bool synthesized = false,
|
||||||
}) : super(
|
}) : super(
|
||||||
timeStamp: timeStamp,
|
timeStamp: timeStamp,
|
||||||
@ -518,6 +524,7 @@ class PointerMoveEvent extends PointerEvent {
|
|||||||
radiusMax: radiusMax,
|
radiusMax: radiusMax,
|
||||||
orientation: orientation,
|
orientation: orientation,
|
||||||
tilt: tilt,
|
tilt: tilt,
|
||||||
|
platformData: platformData,
|
||||||
synthesized: synthesized,
|
synthesized: synthesized,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -447,16 +447,21 @@ class _MotionEventsDispatcher {
|
|||||||
final int pointerIdx = pointers.indexOf(event.pointer);
|
final int pointerIdx = pointers.indexOf(event.pointer);
|
||||||
final int numPointers = pointers.length;
|
final int numPointers = pointers.length;
|
||||||
|
|
||||||
|
// This value must match the value in engine's FlutterView.java.
|
||||||
|
// This flag indicates whether the original Android pointer events were batched together.
|
||||||
|
const int kPointerDataFlagBatched = 1;
|
||||||
|
|
||||||
// Android MotionEvent objects can batch information on multiple pointers.
|
// Android MotionEvent objects can batch information on multiple pointers.
|
||||||
// Flutter breaks these such batched events into multiple PointerEvent objects.
|
// Flutter breaks these such batched events into multiple PointerEvent objects.
|
||||||
// When there are multiple active pointers we accumulate the information for all pointers
|
// When there are multiple active pointers we accumulate the information for all pointers
|
||||||
// as we get PointerEvents, and only send it to the embedded Android view when
|
// as we get PointerEvents, and only send it to the embedded Android view when
|
||||||
// we see the last pointer. This way we achieve the same batching as Android.
|
// we see the last pointer. This way we achieve the same batching as Android.
|
||||||
if(isSinglePointerAction(event) && pointerIdx < numPointers - 1)
|
if (event.platformData == kPointerDataFlagBatched ||
|
||||||
|
(isSinglePointerAction(event) && pointerIdx < numPointers - 1))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int action;
|
int action;
|
||||||
switch(event.runtimeType){
|
switch (event.runtimeType) {
|
||||||
case PointerDownEvent:
|
case PointerDownEvent:
|
||||||
action = numPointers == 1 ? AndroidViewController.kActionDown
|
action = numPointers == 1 ? AndroidViewController.kActionDown
|
||||||
: AndroidViewController.pointerAction(pointerIdx, AndroidViewController.kActionPointerDown);
|
: AndroidViewController.pointerAction(pointerIdx, AndroidViewController.kActionPointerDown);
|
||||||
|
@ -1806,6 +1806,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
await expectLater(
|
await expectLater(
|
||||||
layer.toImage(renderObject.semanticBounds.inflate(50.0)),
|
layer.toImage(renderObject.semanticBounds.inflate(50.0)),
|
||||||
matchesGoldenFile('inspector.repaint_boundary_margin.png'),
|
matchesGoldenFile('inspector.repaint_boundary_margin.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Regression test for how rendering with a pixel scale other than 1.0
|
// Regression test for how rendering with a pixel scale other than 1.0
|
||||||
@ -1816,6 +1817,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
pixelRatio: 0.5,
|
pixelRatio: 0.5,
|
||||||
),
|
),
|
||||||
matchesGoldenFile('inspector.repaint_boundary_margin_small.png'),
|
matchesGoldenFile('inspector.repaint_boundary_margin_small.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
|
|
||||||
await expectLater(
|
await expectLater(
|
||||||
@ -1824,6 +1826,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
pixelRatio: 2.0,
|
pixelRatio: 2.0,
|
||||||
),
|
),
|
||||||
matchesGoldenFile('inspector.repaint_boundary_margin_large.png'),
|
matchesGoldenFile('inspector.repaint_boundary_margin_large.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
|
|
||||||
final Layer layerParent = layer.parent;
|
final Layer layerParent = layer.parent;
|
||||||
@ -1839,6 +1842,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
height: 300.0,
|
height: 300.0,
|
||||||
),
|
),
|
||||||
matchesGoldenFile('inspector.repaint_boundary.png'),
|
matchesGoldenFile('inspector.repaint_boundary.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Verify that taking a screenshot didn't change the layers associated with
|
// Verify that taking a screenshot didn't change the layers associated with
|
||||||
@ -1856,6 +1860,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
margin: 50.0,
|
margin: 50.0,
|
||||||
),
|
),
|
||||||
matchesGoldenFile('inspector.repaint_boundary_margin.png'),
|
matchesGoldenFile('inspector.repaint_boundary_margin.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Verify that taking a screenshot didn't change the layers associated with
|
// Verify that taking a screenshot didn't change the layers associated with
|
||||||
@ -1876,6 +1881,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
debugPaint: true,
|
debugPaint: true,
|
||||||
),
|
),
|
||||||
matchesGoldenFile('inspector.repaint_boundary_debugPaint.png'),
|
matchesGoldenFile('inspector.repaint_boundary_debugPaint.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
// Verify that taking a screenshot with debug paint on did not change
|
// Verify that taking a screenshot with debug paint on did not change
|
||||||
// the number of children the layer has.
|
// the number of children the layer has.
|
||||||
@ -1886,6 +1892,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
await expectLater(
|
await expectLater(
|
||||||
find.byType(RepaintBoundaryWithDebugPaint),
|
find.byType(RepaintBoundaryWithDebugPaint),
|
||||||
matchesGoldenFile('inspector.repaint_boundary.png'),
|
matchesGoldenFile('inspector.repaint_boundary.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(renderObject.debugLayer, equals(layer));
|
expect(renderObject.debugLayer, equals(layer));
|
||||||
@ -1899,6 +1906,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
height: 100.0,
|
height: 100.0,
|
||||||
),
|
),
|
||||||
matchesGoldenFile('inspector.container.png'),
|
matchesGoldenFile('inspector.container.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
|
|
||||||
await expectLater(
|
await expectLater(
|
||||||
@ -1909,6 +1917,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
debugPaint: true,
|
debugPaint: true,
|
||||||
),
|
),
|
||||||
matchesGoldenFile('inspector.container_debugPaint.png'),
|
matchesGoldenFile('inspector.container_debugPaint.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -1929,6 +1938,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
debugPaint: true,
|
debugPaint: true,
|
||||||
),
|
),
|
||||||
matchesGoldenFile('inspector.container_debugPaint.png'),
|
matchesGoldenFile('inspector.container_debugPaint.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
expect(container.debugNeedsLayout, isFalse);
|
expect(container.debugNeedsLayout, isFalse);
|
||||||
}
|
}
|
||||||
@ -1941,6 +1951,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
height: 100.0,
|
height: 100.0,
|
||||||
),
|
),
|
||||||
matchesGoldenFile('inspector.container_small.png'),
|
matchesGoldenFile('inspector.container_small.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
|
|
||||||
await expectLater(
|
await expectLater(
|
||||||
@ -1951,6 +1962,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
maxPixelRatio: 3.0,
|
maxPixelRatio: 3.0,
|
||||||
),
|
),
|
||||||
matchesGoldenFile('inspector.container_large.png'),
|
matchesGoldenFile('inspector.container_large.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
|
|
||||||
// This screenshot will show the clip rect debug paint but no other
|
// This screenshot will show the clip rect debug paint but no other
|
||||||
@ -1963,6 +1975,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
debugPaint: true,
|
debugPaint: true,
|
||||||
),
|
),
|
||||||
matchesGoldenFile('inspector.clipRect_debugPaint.png'),
|
matchesGoldenFile('inspector.clipRect_debugPaint.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
|
|
||||||
final Element clipRect = find.byType(ClipRRect).evaluate().single;
|
final Element clipRect = find.byType(ClipRRect).evaluate().single;
|
||||||
@ -2007,6 +2020,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
await expectLater(
|
await expectLater(
|
||||||
screenshotImage,
|
screenshotImage,
|
||||||
matchesReferenceImage(await clipRectScreenshot),
|
matchesReferenceImage(await clipRectScreenshot),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test with a very visible debug paint
|
// Test with a very visible debug paint
|
||||||
@ -2018,6 +2032,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
debugPaint: true,
|
debugPaint: true,
|
||||||
),
|
),
|
||||||
matchesGoldenFile('inspector.padding_debugPaint.png'),
|
matchesGoldenFile('inspector.padding_debugPaint.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
|
|
||||||
// The bounds for this box crop its rendered content.
|
// The bounds for this box crop its rendered content.
|
||||||
@ -2029,6 +2044,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
debugPaint: true,
|
debugPaint: true,
|
||||||
),
|
),
|
||||||
matchesGoldenFile('inspector.sizedBox_debugPaint.png'),
|
matchesGoldenFile('inspector.sizedBox_debugPaint.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Verify that setting a margin includes the previously cropped content.
|
// Verify that setting a margin includes the previously cropped content.
|
||||||
@ -2041,6 +2057,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
debugPaint: true,
|
debugPaint: true,
|
||||||
),
|
),
|
||||||
matchesGoldenFile('inspector.sizedBox_debugPaint_margin.png'),
|
matchesGoldenFile('inspector.sizedBox_debugPaint_margin.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -2112,6 +2129,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
await expectLater(
|
await expectLater(
|
||||||
find.byKey(mainStackKey),
|
find.byKey(mainStackKey),
|
||||||
matchesGoldenFile('inspector.composited_transform.only_offsets.png'),
|
matchesGoldenFile('inspector.composited_transform.only_offsets.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
|
|
||||||
await expectLater(
|
await expectLater(
|
||||||
@ -2121,11 +2139,13 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
height: 500.0,
|
height: 500.0,
|
||||||
),
|
),
|
||||||
matchesGoldenFile('inspector.composited_transform.only_offsets_follower.png'),
|
matchesGoldenFile('inspector.composited_transform.only_offsets_follower.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
|
|
||||||
await expectLater(
|
await expectLater(
|
||||||
WidgetInspectorService.instance.screenshot(find.byType(Stack).evaluate().first, width: 300.0, height: 300.0),
|
WidgetInspectorService.instance.screenshot(find.byType(Stack).evaluate().first, width: 300.0, height: 300.0),
|
||||||
matchesGoldenFile('inspector.composited_transform.only_offsets_small.png'),
|
matchesGoldenFile('inspector.composited_transform.only_offsets_small.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
|
|
||||||
await expectLater(
|
await expectLater(
|
||||||
@ -2135,6 +2155,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
height: 500.0,
|
height: 500.0,
|
||||||
),
|
),
|
||||||
matchesGoldenFile('inspector.composited_transform.only_offsets_target.png'),
|
matchesGoldenFile('inspector.composited_transform.only_offsets_target.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -2207,6 +2228,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
await expectLater(
|
await expectLater(
|
||||||
find.byKey(mainStackKey),
|
find.byKey(mainStackKey),
|
||||||
matchesGoldenFile('inspector.composited_transform.with_rotations.png'),
|
matchesGoldenFile('inspector.composited_transform.with_rotations.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
|
|
||||||
await expectLater(
|
await expectLater(
|
||||||
@ -2216,6 +2238,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
height: 500.0,
|
height: 500.0,
|
||||||
),
|
),
|
||||||
matchesGoldenFile('inspector.composited_transform.with_rotations_small.png'),
|
matchesGoldenFile('inspector.composited_transform.with_rotations_small.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
|
|
||||||
await expectLater(
|
await expectLater(
|
||||||
@ -2225,6 +2248,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
height: 500.0,
|
height: 500.0,
|
||||||
),
|
),
|
||||||
matchesGoldenFile('inspector.composited_transform.with_rotations_target.png'),
|
matchesGoldenFile('inspector.composited_transform.with_rotations_target.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
|
|
||||||
await expectLater(
|
await expectLater(
|
||||||
@ -2234,6 +2258,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
|||||||
height: 500.0,
|
height: 500.0,
|
||||||
),
|
),
|
||||||
matchesGoldenFile('inspector.composited_transform.with_rotations_follower.png'),
|
matchesGoldenFile('inspector.composited_transform.with_rotations_follower.png'),
|
||||||
|
skip: !Platform.isLinux,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Make sure taking screenshots hasn't modified the positions of the
|
// Make sure taking screenshots hasn't modified the positions of the
|
||||||
|
Loading…
Reference in New Issue
Block a user