mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Fix non-vd android platform view input event offsets (flutter/engine#52532)
Fixes https://github.com/flutter/flutter/issues/146570, which tracks a regression from https://github.com/flutter/engine/pull/49268 regarding platform view inputs in some specific cases. This PR translates the input event location to be the same as the location we calculated before https://github.com/flutter/engine/pull/49268, returning to the previous behavior, while maintaining the input event's verified status (I checked this manually with the `InputManager`). Tested manually with the reproduction in the linked issue. [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
This commit is contained in:
parent
98713e6aa6
commit
b6bb39ad2d
@ -501,7 +501,12 @@ public class PlatformViewsChannel {
|
||||
public final int action;
|
||||
/** The number of pointers (e.g, fingers) involved in the touch event. */
|
||||
public final int pointerCount;
|
||||
/** Properties for each pointer, encoded in a raw format. */
|
||||
/**
|
||||
* Properties for each pointer, encoded in a raw format.
|
||||
* Expected to be formatted as a List[List[Integer]], where each inner list has two items:
|
||||
* - An id, at index 0, corresponding to {@link android.view.MotionEvent.PointerProperties#id}
|
||||
* - A tool type, at index 1, corresponding to {@link android.view.MotionEvent.PointerProperties#toolType}.
|
||||
* */
|
||||
@NonNull public final Object rawPointerPropertiesList;
|
||||
/** Coordinates for each pointer, encoded in a raw format. */
|
||||
@NonNull public final Object rawPointerCoords;
|
||||
|
||||
@ -4,8 +4,6 @@
|
||||
|
||||
package io.flutter.plugin.platform;
|
||||
|
||||
import static android.view.MotionEvent.PointerCoords;
|
||||
import static android.view.MotionEvent.PointerProperties;
|
||||
import static io.flutter.Build.API_LEVELS;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
@ -668,6 +666,25 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
|
||||
return textureId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates an original touch event to have the same locations as the ones that Flutter
|
||||
* calculates (because original + flutter's - original = flutter's).
|
||||
*
|
||||
* @param originalEvent The saved original input event.
|
||||
* @param pointerCoords The coordinates that Flutter thinks the touch is happening at.
|
||||
*/
|
||||
private static void translateMotionEvent(
|
||||
MotionEvent originalEvent, PointerCoords[] pointerCoords) {
|
||||
if (pointerCoords.length < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
float xOffset = pointerCoords[0].x - originalEvent.getX();
|
||||
float yOffset = pointerCoords[0].y - originalEvent.getY();
|
||||
|
||||
originalEvent.offsetLocation(xOffset, yOffset);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public MotionEvent toMotionEvent(
|
||||
float density, PlatformViewsChannel.PlatformViewTouch touch, boolean usingVirtualDiplay) {
|
||||
@ -675,25 +692,27 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
|
||||
MotionEventTracker.MotionEventId.from(touch.motionEventId);
|
||||
MotionEvent trackedEvent = motionEventTracker.pop(motionEventId);
|
||||
|
||||
// Pointer coordinates in the tracked events are global to FlutterView
|
||||
// The framework converts them to be local to a widget, given that
|
||||
// motion events operate on local coords, we need to replace these in the tracked
|
||||
// event with their local counterparts.
|
||||
// Compute this early so it can be used as input to translateNonVirtualDisplayMotionEvent.
|
||||
PointerCoords[] pointerCoords =
|
||||
parsePointerCoordsList(touch.rawPointerCoords, density)
|
||||
.toArray(new PointerCoords[touch.pointerCount]);
|
||||
|
||||
if (!usingVirtualDiplay && trackedEvent != null) {
|
||||
// We have the original event, deliver it as it will pass the verifiable
|
||||
// We have the original event, deliver it after offsetting as it will pass the verifiable
|
||||
// input check.
|
||||
translateMotionEvent(trackedEvent, pointerCoords);
|
||||
return trackedEvent;
|
||||
}
|
||||
// We are in virtual display mode or don't have a reference to the original MotionEvent.
|
||||
// In this case we manually recreate a MotionEvent to be delivered. This MotionEvent
|
||||
// will fail the verifiable input check.
|
||||
|
||||
// Pointer coordinates in the tracked events are global to FlutterView
|
||||
// framework converts them to be local to a widget, given that
|
||||
// motion events operate on local coords, we need to replace these in the tracked
|
||||
// event with their local counterparts.
|
||||
PointerProperties[] pointerProperties =
|
||||
parsePointerPropertiesList(touch.rawPointerPropertiesList)
|
||||
.toArray(new PointerProperties[touch.pointerCount]);
|
||||
PointerCoords[] pointerCoords =
|
||||
parsePointerCoordsList(touch.rawPointerCoords, density)
|
||||
.toArray(new PointerCoords[touch.pointerCount]);
|
||||
|
||||
// TODO (kaushikiska) : warn that we are potentially using an untracked
|
||||
// event in the platform views.
|
||||
|
||||
@ -361,34 +361,48 @@ public class PlatformViewsControllerTest {
|
||||
assertNotEquals(resolvedEvent.getAction(), frameWorkTouch.action);
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void itUsesActionEventTypeFromMotionEventForHybridPlatformViews() {
|
||||
MotionEventTracker motionEventTracker = MotionEventTracker.getInstance();
|
||||
PlatformViewsController platformViewsController = new PlatformViewsController();
|
||||
|
||||
MotionEvent original =
|
||||
MotionEvent.obtain(
|
||||
100, // downTime
|
||||
100, // eventTime
|
||||
1, // action
|
||||
0, // x
|
||||
0, // y
|
||||
0 // metaState
|
||||
);
|
||||
|
||||
// track an event that will later get passed to us from framework
|
||||
private MotionEvent makePlatformViewTouchAndInvokeToMotionEvent(
|
||||
PlatformViewsController platformViewsController,
|
||||
MotionEventTracker motionEventTracker,
|
||||
MotionEvent original,
|
||||
boolean usingVirtualDisplays) {
|
||||
MotionEventTracker.MotionEventId motionEventId = motionEventTracker.track(original);
|
||||
|
||||
PlatformViewTouch frameWorkTouch =
|
||||
// Construct a PlatformViewTouch.rawPointerPropertiesList by doing the inverse of
|
||||
// PlatformViewsController.parsePointerPropertiesList.
|
||||
List<List<Integer>> pointerProperties =
|
||||
Arrays.asList(
|
||||
Arrays.asList(
|
||||
original.getPointerId(0),
|
||||
original.getToolType(0)
|
||||
)
|
||||
);
|
||||
// Construct a PlatformViewTouch.rawPointerCoords by doing the inverse of
|
||||
// PlatformViewsController.parsePointerCoordsList.
|
||||
List<List<Double>> pointerCoordinates =
|
||||
Arrays.asList(
|
||||
Arrays.asList(
|
||||
(double) original.getOrientation(),
|
||||
(double) original.getPressure(),
|
||||
(double) original.getSize(),
|
||||
(double) original.getToolMajor(),
|
||||
(double) original.getToolMinor(),
|
||||
(double) original.getTouchMajor(),
|
||||
(double) original.getTouchMinor(),
|
||||
(double) original.getX(),
|
||||
(double) original.getY()
|
||||
)
|
||||
);
|
||||
// Make a platform view touch from the motion event.
|
||||
PlatformViewTouch frameWorkTouchNonVd =
|
||||
new PlatformViewTouch(
|
||||
0, // viewId
|
||||
original.getDownTime(),
|
||||
original.getEventTime(),
|
||||
2, // action
|
||||
original.getAction(),
|
||||
1, // pointerCount
|
||||
Arrays.asList(Arrays.asList(0, 0)), // pointer properties
|
||||
Arrays.asList(Arrays.asList(0., 1., 2., 3., 4., 5., 6., 7., 8.)), // pointer coords
|
||||
pointerProperties, // pointer properties
|
||||
pointerCoordinates, // pointer coords
|
||||
original.getMetaState(),
|
||||
original.getButtonState(),
|
||||
original.getXPrecision(),
|
||||
@ -399,11 +413,38 @@ public class PlatformViewsControllerTest {
|
||||
original.getFlags(),
|
||||
motionEventId.getId());
|
||||
|
||||
MotionEvent resolvedEvent =
|
||||
platformViewsController.toMotionEvent(
|
||||
/*density=*/ 1, frameWorkTouch, /*usingVirtualDisplay=*/ false);
|
||||
return platformViewsController.toMotionEvent(
|
||||
1, // density
|
||||
frameWorkTouchNonVd,
|
||||
usingVirtualDisplays);
|
||||
}
|
||||
|
||||
assertEquals(resolvedEvent.getAction(), frameWorkTouch.action);
|
||||
@Test
|
||||
public void toMotionEvent_returnsSameCoordsForVdAndNonVd() {
|
||||
MotionEventTracker motionEventTracker = MotionEventTracker.getInstance();
|
||||
PlatformViewsController platformViewsController = new PlatformViewsController();
|
||||
|
||||
MotionEvent original =
|
||||
MotionEvent.obtain(
|
||||
10, // downTime
|
||||
10, // eventTime
|
||||
261, // action
|
||||
1, // x
|
||||
1, // y
|
||||
0 // metaState
|
||||
);
|
||||
|
||||
MotionEvent resolvedNonVdEvent =
|
||||
makePlatformViewTouchAndInvokeToMotionEvent(
|
||||
platformViewsController, motionEventTracker, original, false);
|
||||
|
||||
MotionEvent resolvedVdEvent =
|
||||
makePlatformViewTouchAndInvokeToMotionEvent(
|
||||
platformViewsController, motionEventTracker, original, true);
|
||||
|
||||
assertEquals(resolvedVdEvent.getEventTime(), resolvedNonVdEvent.getEventTime());
|
||||
assertEquals(resolvedVdEvent.getX(), resolvedNonVdEvent.getX(), 0.001f);
|
||||
assertEquals(resolvedVdEvent.getY(), resolvedNonVdEvent.getY(), 0.001f);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user