Skip to content

Commit

Permalink
Integrated AndroidTouchProcessor within the old FlutterView (flutter#…
Browse files Browse the repository at this point in the history
  • Loading branch information
matthew-carroll authored Mar 11, 2019
1 parent bc90132 commit 20165b3
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 215 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.flutter.embedding.engine.android;

import android.os.Build;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.view.InputDevice;
Expand Down Expand Up @@ -36,7 +37,6 @@ public class AndroidTouchProcessor {
int UP = 6;
}


// Must match the PointerDeviceKind enum in pointer.dart.
@IntDef({
PointerDeviceKind.TOUCH,
Expand All @@ -53,10 +53,24 @@ public class AndroidTouchProcessor {
int UNKNOWN = 4;
}

// Must match the PointerSignalKind enum in pointer.dart.
@IntDef({
PointerSignalKind.NONE,
PointerSignalKind.SCROLL,
PointerSignalKind.UNKNOWN
})
private @interface PointerSignalKind {
int NONE = 0;
int SCROLL = 1;
int UNKNOWN = 2;
}

// Must match the unpacking code in hooks.dart.
// TODO(mattcarroll): Update with additional fields for scroll wheel support
private static final int POINTER_DATA_FIELD_COUNT = 21;
private static final int POINTER_DATA_FIELD_COUNT = 24;
private static final int BYTES_PER_FIELD = 8;

// This value must match the value in framework's platform_view.dart.
// This flag indicates whether the original Android pointer events were batched together.
private static final int POINTER_DATA_FLAG_BATCHED = 1;

@NonNull
Expand Down Expand Up @@ -114,14 +128,45 @@ public boolean onTouchEvent(MotionEvent event) {
}

// Verify that the packet is the expected size.
assert packet.position() % (POINTER_DATA_FIELD_COUNT * BYTES_PER_FIELD) == 0;
if (packet.position() % (POINTER_DATA_FIELD_COUNT * BYTES_PER_FIELD) != 0) {
throw new AssertionError("Packet position is not on field boundary");
}

// Send the packet to Flutter.
renderer.dispatchPointerDataPacket(packet, packet.position());

return true;
}

/**
* Sends the given generic {@link MotionEvent} data to Flutter in a format that Flutter
* understands.
*
* Generic motion events include joystick movement, mouse hover, track pad touches, scroll wheel
* movements, etc.
*/
public boolean onGenericMotionEvent(MotionEvent event) {
// Method isFromSource is only available in API 18+ (Jelly Bean MR2)
// Mouse hover support is not implemented for API < 18.
boolean isPointerEvent = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2
&& event.isFromSource(InputDevice.SOURCE_CLASS_POINTER);
if (!isPointerEvent || event.getActionMasked() != MotionEvent.ACTION_HOVER_MOVE) {
return false;
}

int pointerChange = getPointerChangeForAction(event.getActionMasked());
ByteBuffer packet = ByteBuffer.allocateDirect(
event.getPointerCount() * POINTER_DATA_FIELD_COUNT * BYTES_PER_FIELD
);
packet.order(ByteOrder.LITTLE_ENDIAN);

// ACTION_HOVER_MOVE always applies to a single pointer only.
addPointerForIndex(event, event.getActionIndex(), pointerChange, 0, packet);
assert(packet.position() % (POINTER_DATA_FIELD_COUNT * BYTES_PER_FIELD) != 0);
renderer.dispatchPointerDataPacket(packet, packet.position());
return true;
}

// TODO(mattcarroll): consider creating a PointerPacket class instead of using a procedure that mutates inputs.
private void addPointerForIndex(
MotionEvent event,
Expand All @@ -136,11 +181,14 @@ private void addPointerForIndex(

int pointerKind = getPointerDeviceTypeForToolType(event.getToolType(pointerIndex));

int signalKind = PointerSignalKind.NONE;

long timeStamp = event.getEventTime() * 1000; // Convert from milliseconds to microseconds.

packet.putLong(timeStamp); // time_stamp
packet.putLong(pointerChange); // change
packet.putLong(pointerKind); // kind
packet.putLong(signalKind); // signal_kind
packet.putLong(event.getPointerId(pointerIndex)); // device
packet.putDouble(event.getX(pointerIndex)); // physical_x
packet.putDouble(event.getY(pointerIndex)); // physical_y
Expand Down Expand Up @@ -192,7 +240,10 @@ private void addPointerForIndex(
packet.putDouble(0.0); // tilt
}

packet.putLong(pointerData);
packet.putLong(pointerData); // platformData

packet.putDouble(0.0); // scroll_delta_x
packet.putDouble(0.0); // scroll_delta_y
}

@PointerChange
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,12 +312,34 @@ public boolean onKeyDown(int keyCode, KeyEvent event) {
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!isAttachedToFlutterEngine()) {
return false;
return super.onTouchEvent(event);
}

// TODO(abarth): This version check might not be effective in some
// versions of Android that statically compile code and will be upset
// at the lack of |requestUnbufferedDispatch|. Instead, we should factor
// version-dependent code into separate classes for each supported
// version and dispatch dynamically.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
requestUnbufferedDispatch(event);
}

return androidTouchProcessor.onTouchEvent(event);
}

/**
* Invoked by Android when a generic motion event occurs, e.g., joystick movement, mouse hover,
* track pad touches, scroll wheel movements, etc.
*
* Flutter handles all of its own gesture detection and processing, therefore this
* method forwards all {@link MotionEvent} data from Android to Flutter.
*/
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
boolean handled = isAttachedToFlutterEngine() && androidTouchProcessor.onGenericMotionEvent(event);
return handled ? true : super.onGenericMotionEvent(event);
}

/**
* Invoked by Android when a hover-compliant input system causes a hover event.
*
Expand All @@ -332,7 +354,7 @@ public boolean onTouchEvent(MotionEvent event) {
@Override
public boolean onHoverEvent(MotionEvent event) {
if (!isAttachedToFlutterEngine()) {
return false;
return super.onHoverEvent(event);
}

// TODO(mattcarroll): hook up to accessibility.
Expand Down
Loading

0 comments on commit 20165b3

Please sign in to comment.