Bug 1249915 - Add ability to synthesize native touch events on Fennec for mochitests. r=snorp

MozReview-Commit-ID: Dit8QhqJSYc
This commit is contained in:
Kartikaya Gupta 2016-02-23 10:17:46 -05:00
parent 6fb25463b4
commit 650f50e205
5 changed files with 214 additions and 0 deletions

View File

@ -23,6 +23,8 @@ import android.graphics.RectF;
import android.os.SystemClock;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.InputDevice;
import android.view.MotionEvent;
import org.json.JSONObject;
import java.util.ArrayList;
@ -106,6 +108,8 @@ class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
*/
private volatile boolean mContentDocumentIsDisplayed;
private SynthesizedEventState mPointerState;
public GeckoLayerClient(Context context, LayerView view, EventDispatcher eventDispatcher) {
// we can fill these in with dummy values because they are always written
// to before being read
@ -709,6 +713,141 @@ class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
layersUpdated, paintSyncId);
}
class PointerInfo {
public int pointerId;
public int screenX;
public int screenY;
public double pressure;
public int orientation;
public MotionEvent.PointerCoords getCoords() {
MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
coords.orientation = orientation;
coords.pressure = (float)pressure;
coords.x = screenX;
coords.y = screenY;
return coords;
}
}
class SynthesizedEventState {
public final ArrayList<PointerInfo> pointers;
public long downTime;
SynthesizedEventState() {
pointers = new ArrayList<PointerInfo>();
}
int getPointerIndex(int pointerId) {
for (int i = 0; i < pointers.size(); i++) {
if (pointers.get(i).pointerId == pointerId) {
return i;
}
}
return -1;
}
int addPointer(int pointerId) {
PointerInfo info = new PointerInfo();
info.pointerId = pointerId;
pointers.add(info);
return pointers.size() - 1;
}
int[] getPointerIds() {
int[] ids = new int[pointers.size()];
for (int i = 0; i < ids.length; i++) {
ids[i] = pointers.get(i).pointerId;
}
return ids;
}
MotionEvent.PointerCoords[] getPointerCoords() {
MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[pointers.size()];
for (int i = 0; i < coords.length; i++) {
coords[i] = pointers.get(i).getCoords();
}
return coords;
}
}
@WrapForJNI
public void synthesizeNativeTouchPoint(int pointerId, int eventType, int screenX,
int screenY, double pressure, int orientation)
{
if (mPointerState == null) {
mPointerState = new SynthesizedEventState();
}
// Find the pointer if it already exists
int pointerIndex = mPointerState.getPointerIndex(pointerId);
// Event-specific handling
switch (eventType) {
case MotionEvent.ACTION_POINTER_UP:
if (pointerIndex < 0) {
Log.d(LOGTAG, "Requested synthesis of a pointer-up for a pointer that doesn't exist!");
return;
}
if (mPointerState.pointers.size() == 1) {
// Last pointer is going up
eventType = MotionEvent.ACTION_UP;
}
break;
case MotionEvent.ACTION_CANCEL:
if (pointerIndex < 0) {
Log.d(LOGTAG, "Requested synthesis of a pointer-cancel for a pointer that doesn't exist!");
return;
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
if (pointerIndex < 0) {
// Adding a new pointer
pointerIndex = mPointerState.addPointer(pointerId);
if (pointerIndex == 0) {
// first pointer
eventType = MotionEvent.ACTION_DOWN;
mPointerState.downTime = SystemClock.uptimeMillis();
}
} else {
// We're moving an existing pointer
eventType = MotionEvent.ACTION_MOVE;
}
break;
}
// Update the pointer with the new info
PointerInfo info = mPointerState.pointers.get(pointerIndex);
info.screenX = screenX;
info.screenY = screenY;
info.pressure = pressure;
info.orientation = orientation;
// Dispatch the event
int action = (pointerIndex << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
action &= MotionEvent.ACTION_POINTER_INDEX_MASK;
action |= (eventType & MotionEvent.ACTION_MASK);
final MotionEvent event = MotionEvent.obtain(mPointerState.downTime,
SystemClock.uptimeMillis(), action, mPointerState.pointers.size(),
mPointerState.getPointerIds(), mPointerState.getPointerCoords(),
0, 0, 0, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
mView.post(new Runnable() {
@Override
public void run() {
event.offsetLocation(0, mView.getSurfaceTranslation());
mView.dispatchTouchEvent(event);
}
});
// Forget about removed pointers
if (eventType == MotionEvent.ACTION_POINTER_UP ||
eventType == MotionEvent.ACTION_UP ||
eventType == MotionEvent.ACTION_CANCEL)
{
mPointerState.pointers.remove(pointerIndex);
}
}
@WrapForJNI(allowMultithread = true)
public LayerRenderer.Frame createFrame() {
// Create the shaders and textures if necessary.

View File

@ -1437,6 +1437,14 @@ auto GeckoLayerClient::SyncViewportInfo(int32_t a0, int32_t a1, int32_t a2, int3
return mozilla::jni::Method<SyncViewportInfo_t>::Call(GeckoLayerClient::mCtx, nullptr, a0, a1, a2, a3, a4, a5, a6);
}
constexpr char GeckoLayerClient::SynthesizeNativeTouchPoint_t::name[];
constexpr char GeckoLayerClient::SynthesizeNativeTouchPoint_t::signature[];
auto GeckoLayerClient::SynthesizeNativeTouchPoint(int32_t a0, int32_t a1, int32_t a2, int32_t a3, double a4, int32_t a5) const -> void
{
return mozilla::jni::Method<SynthesizeNativeTouchPoint_t>::Call(GeckoLayerClient::mCtx, nullptr, a0, a1, a2, a3, a4, a5);
}
template<> const char mozilla::jni::Context<ImmutableViewportMetrics, jobject>::name[] =
"org/mozilla/gecko/gfx/ImmutableViewportMetrics";

View File

@ -3370,6 +3370,27 @@ public:
auto SyncViewportInfo(int32_t, int32_t, int32_t, int32_t, float, bool, int32_t) const -> mozilla::jni::Object::LocalRef;
struct SynthesizeNativeTouchPoint_t {
typedef GeckoLayerClient Owner;
typedef void ReturnType;
typedef void SetterType;
typedef mozilla::jni::Args<
int32_t,
int32_t,
int32_t,
int32_t,
double,
int32_t> Args;
static constexpr char name[] = "synthesizeNativeTouchPoint";
static constexpr char signature[] =
"(IIIIDI)V";
static const bool isStatic = false;
static const mozilla::jni::ExceptionMode exceptionMode =
mozilla::jni::ExceptionMode::ABORT;
};
auto SynthesizeNativeTouchPoint(int32_t, int32_t, int32_t, int32_t, double, int32_t) const -> void;
static const bool isMultithreaded = true;
};

View File

@ -3263,6 +3263,45 @@ nsWindow::GetIMEUpdatePreference()
nsIMEUpdatePreference::NOTIFY_TEXT_CHANGE);
}
nsresult
nsWindow::SynthesizeNativeTouchPoint(uint32_t aPointerId,
TouchPointerState aPointerState,
ScreenIntPoint aPointerScreenPoint,
double aPointerPressure,
uint32_t aPointerOrientation,
nsIObserver* aObserver)
{
mozilla::widget::AutoObserverNotifier notifier(aObserver, "touchpoint");
int eventType;
switch (aPointerState) {
case TOUCH_CONTACT:
// This could be a ACTION_DOWN or ACTION_MOVE depending on the
// existing state; it is mapped to the right thing in Java.
eventType = sdk::MotionEvent::ACTION_POINTER_DOWN;
break;
case TOUCH_REMOVE:
// This could be turned into a ACTION_UP in Java
eventType = sdk::MotionEvent::ACTION_POINTER_UP;
break;
case TOUCH_CANCEL:
eventType = sdk::MotionEvent::ACTION_CANCEL;
break;
case TOUCH_HOVER: // not supported for now
default:
return NS_ERROR_UNEXPECTED;
}
MOZ_ASSERT(mGLControllerSupport);
GeckoLayerClient::LocalRef client = mGLControllerSupport->GetLayerClient();
client->SynthesizeNativeTouchPoint(aPointerId, eventType,
aPointerScreenPoint.x, aPointerScreenPoint.y, aPointerPressure,
aPointerOrientation);
return NS_OK;
}
void
nsWindow::DrawWindowUnderlay(LayerManagerComposite* aManager,
LayoutDeviceIntRect aRect)

View File

@ -186,6 +186,13 @@ public:
const FrameMetrics::ViewID& aViewId,
const mozilla::Maybe<ZoomConstraints>& aConstraints) override;
nsresult SynthesizeNativeTouchPoint(uint32_t aPointerId,
TouchPointerState aPointerState,
ScreenIntPoint aPointerScreenPoint,
double aPointerPressure,
uint32_t aPointerOrientation,
nsIObserver* aObserver) override;
protected:
void BringToFront();
nsWindow *FindTopLevel();