diff options
| author | Garfield Tan <xutan@google.com> | 2019-07-15 14:00:35 -0700 |
|---|---|---|
| committer | Garfield Tan <xutan@google.com> | 2019-07-30 09:22:27 -0700 |
| commit | 1da8628ae3edf2945dfa2bc1ec43dc848d4ffffb (patch) | |
| tree | 76681508c072633d7a15d210dbc5fcebdc78d139 /core/java/android/view/MotionEvent.java | |
| parent | 2c79b41c80028a1ff57e60fabdedb8db5438f4db (diff) | |
Add cursor position to synthesized events.
Synthesized events consist of injected, split and clamped events.
Instead of letting caller specify it, we fill cursor position fields by
deriving from pointers. Thus we can maintain the property between
pointer coodinates and cursor position. If there is need we can add a
new obtain method later as well anyway.
I decided to update the value for split events because it would be
unnatural to have a out of bound cursor position when a gesture crosses
view boundaries, but ultimately we probably shouldn't split mouse
events. Nevertheless that's out of the scope of this CL and I chose to
be on the safe side at this moment.
Bug: 134788085
Bug: 136607870
Test: atest TooltipTest#testMouseHoverTooltipWithHoverListener
Test: atest MotionEventTest (and select running all candidates)
Test: atest DragDropTest
Change-Id: I4f3dec0f3c4c1ab2ff5cb986b94b0e007d9fe41b
Diffstat (limited to 'core/java/android/view/MotionEvent.java')
| -rw-r--r-- | core/java/android/view/MotionEvent.java | 111 |
1 files changed, 101 insertions, 10 deletions
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index bff3a1dba3f4..bd865c063055 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -1471,6 +1471,10 @@ public final class MotionEvent extends InputEvent implements Parcelable { @UnsupportedAppUsage private static final int HISTORY_CURRENT = -0x80000000; + // This is essentially the same as native AMOTION_EVENT_INVALID_CURSOR_POSITION as they're all + // NaN and we use isnan() everywhere to check validity. + private static final float INVALID_CURSOR_POSITION = Float.NaN; + private static final int MAX_RECYCLED = 10; private static final Object gRecyclerLock = new Object(); private static int gRecyclerUsed; @@ -1590,6 +1594,12 @@ public final class MotionEvent extends InputEvent implements Parcelable { @CriticalNative private static native float nativeGetYPrecision(long nativePtr); @CriticalNative + private static native float nativeGetXCursorPosition(long nativePtr); + @CriticalNative + private static native float nativeGetYCursorPosition(long nativePtr); + @CriticalNative + private static native void nativeSetCursorPosition(long nativePtr, float x, float y); + @CriticalNative private static native long nativeGetDownTimeNanos(long nativePtr); @CriticalNative private static native void nativeSetDownTimeNanos(long nativePtr, long downTime); @@ -1674,12 +1684,11 @@ public final class MotionEvent extends InputEvent implements Parcelable { float xPrecision, float yPrecision, int deviceId, int edgeFlags, int source, int displayId, int flags) { MotionEvent ev = obtain(); - ev.mNativePtr = nativeInitialize(ev.mNativePtr, - deviceId, source, displayId, action, flags, edgeFlags, metaState, buttonState, - CLASSIFICATION_NONE, 0, 0, xPrecision, yPrecision, + final boolean success = ev.initialize(deviceId, source, displayId, action, flags, edgeFlags, + metaState, buttonState, CLASSIFICATION_NONE, 0, 0, xPrecision, yPrecision, downTime * NS_PER_MS, eventTime * NS_PER_MS, pointerCount, pointerProperties, pointerCoords); - if (ev.mNativePtr == 0) { + if (!success) { Log.e(TAG, "Could not initialize MotionEvent"); ev.recycle(); return null; @@ -1859,8 +1868,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { pc[0].pressure = pressure; pc[0].size = size; - ev.mNativePtr = nativeInitialize(ev.mNativePtr, - deviceId, source, displayId, + ev.initialize(deviceId, source, displayId, action, 0, edgeFlags, metaState, 0 /*buttonState*/, CLASSIFICATION_NONE, 0, 0, xPrecision, yPrecision, downTime * NS_PER_MS, eventTime * NS_PER_MS, @@ -1958,6 +1966,22 @@ public final class MotionEvent extends InputEvent implements Parcelable { return ev; } + private boolean initialize(int deviceId, int source, int displayId, int action, int flags, + int edgeFlags, int metaState, int buttonState, @Classification int classification, + float xOffset, float yOffset, float xPrecision, float yPrecision, + long downTimeNanos, long eventTimeNanos, + int pointerCount, PointerProperties[] pointerIds, PointerCoords[] pointerCoords) { + mNativePtr = nativeInitialize(mNativePtr, deviceId, source, displayId, action, flags, + edgeFlags, metaState, buttonState, classification, xOffset, yOffset, + xPrecision, yPrecision, downTimeNanos, eventTimeNanos, pointerCount, pointerIds, + pointerCoords); + if (mNativePtr == 0) { + return false; + } + updateCursorPosition(); + return true; + } + /** @hide */ @Override @UnsupportedAppUsage @@ -2015,7 +2039,11 @@ public final class MotionEvent extends InputEvent implements Parcelable { /** {@inheritDoc} */ @Override public final void setSource(int source) { + if (source == getSource()) { + return; + } nativeSetSource(mNativePtr, source); + updateCursorPosition(); } /** @hide */ @@ -2670,6 +2698,39 @@ public final class MotionEvent extends InputEvent implements Parcelable { } /** + * Returns the x coordinate of mouse cursor position when this event is + * reported. This value is only valid if {@link #getSource()} returns + * {@link InputDevice#SOURCE_MOUSE}. + * + * @hide + */ + public float getXCursorPosition() { + return nativeGetXCursorPosition(mNativePtr); + } + + /** + * Returns the y coordinate of mouse cursor position when this event is + * reported. This value is only valid if {@link #getSource()} returns + * {@link InputDevice#SOURCE_MOUSE}. + * + * @hide + */ + public float getYCursorPosition() { + return nativeGetYCursorPosition(mNativePtr); + } + + /** + * Sets cursor position to given coordinates. The coordinate in parameters should be after + * offsetting. In other words, the effect of this function is {@link #getXCursorPosition()} and + * {@link #getYCursorPosition()} will return the same value passed in the parameters. + * + * @hide + */ + private void setCursorPosition(float x, float y) { + nativeSetCursorPosition(mNativePtr, x, y); + } + + /** * Returns the number of historical points in this event. These are * movements that have occurred between this event and the previous event. * This only applies to ACTION_MOVE events -- all other actions will have @@ -3305,8 +3366,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { pc[i].x = clamp(pc[i].x, left, right); pc[i].y = clamp(pc[i].y, top, bottom); } - ev.mNativePtr = nativeInitialize(ev.mNativePtr, - nativeGetDeviceId(mNativePtr), nativeGetSource(mNativePtr), + ev.initialize(nativeGetDeviceId(mNativePtr), nativeGetSource(mNativePtr), nativeGetDisplayId(mNativePtr), nativeGetAction(mNativePtr), nativeGetFlags(mNativePtr), nativeGetEdgeFlags(mNativePtr), nativeGetMetaState(mNativePtr), @@ -3399,8 +3459,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { final long eventTimeNanos = nativeGetEventTimeNanos(mNativePtr, historyPos); if (h == 0) { - ev.mNativePtr = nativeInitialize(ev.mNativePtr, - nativeGetDeviceId(mNativePtr), nativeGetSource(mNativePtr), + ev.initialize(nativeGetDeviceId(mNativePtr), nativeGetSource(mNativePtr), nativeGetDisplayId(mNativePtr), newAction, nativeGetFlags(mNativePtr), nativeGetEdgeFlags(mNativePtr), nativeGetMetaState(mNativePtr), @@ -3417,6 +3476,38 @@ public final class MotionEvent extends InputEvent implements Parcelable { } } + /** + * Calculate new cursor position for events from mouse. This is used to split, clamp and inject + * events. + * + * <p>If the source is mouse, it sets cursor position to the centroid of all pointers because + * InputReader maps multiple fingers on a touchpad to locations around cursor position in screen + * coordinates so that the mouse cursor is at the centroid of all pointers. + * + * <p>If the source is not mouse it sets cursor position to NaN. + */ + private void updateCursorPosition() { + if (getSource() != InputDevice.SOURCE_MOUSE) { + setCursorPosition(INVALID_CURSOR_POSITION, INVALID_CURSOR_POSITION); + return; + } + + float x = 0; + float y = 0; + + final int pointerCount = getPointerCount(); + for (int i = 0; i < pointerCount; ++i) { + x += getX(i); + y += getY(i); + } + + // If pointer count is 0, divisions below yield NaN, which is an acceptable result for this + // corner case. + x /= pointerCount; + y /= pointerCount; + setCursorPosition(x, y); + } + @Override public String toString() { StringBuilder msg = new StringBuilder(); |
