diff options
27 files changed, 1989 insertions, 873 deletions
diff --git a/api/current.txt b/api/current.txt index 12fa844..86703ba 100644 --- a/api/current.txt +++ b/api/current.txt @@ -20158,6 +20158,7 @@ package android.view { field public static final int SOURCE_JOYSTICK = 16777232; // 0x1000010 field public static final int SOURCE_KEYBOARD = 257; // 0x101 field public static final int SOURCE_MOUSE = 8194; // 0x2002 + field public static final int SOURCE_STYLUS = 16386; // 0x4002 field public static final int SOURCE_TOUCHPAD = 1048584; // 0x100008 field public static final int SOURCE_TOUCHSCREEN = 4098; // 0x1002 field public static final int SOURCE_TRACKBALL = 65540; // 0x10004 @@ -20690,6 +20691,7 @@ package android.view { method public final int getActionMasked(); method public final float getAxisValue(int); method public final float getAxisValue(int, int); + method public final int getButtonState(); method public final int getDeviceId(); method public final long getDownTime(); method public final int getEdgeFlags(); @@ -20724,6 +20726,7 @@ package android.view { method public final void getPointerCoords(int, android.view.MotionEvent.PointerCoords); method public final int getPointerCount(); method public final int getPointerId(int); + method public final void getPointerProperties(int, android.view.MotionEvent.PointerProperties); method public final float getPressure(); method public final float getPressure(int); method public final float getRawX(); @@ -20735,6 +20738,7 @@ package android.view { method public final float getToolMajor(int); method public final float getToolMinor(); method public final float getToolMinor(int); + method public final int getToolType(int); method public final float getTouchMajor(); method public final float getTouchMajor(int); method public final float getTouchMinor(); @@ -20745,7 +20749,8 @@ package android.view { method public final float getY(); method public final float getY(int); method public final float getYPrecision(); - method public static android.view.MotionEvent obtain(long, long, int, int, int[], android.view.MotionEvent.PointerCoords[], int, float, float, int, int, int, int); + method public static android.view.MotionEvent obtain(long, long, int, int, android.view.MotionEvent.PointerProperties[], android.view.MotionEvent.PointerCoords[], int, int, float, float, int, int, int, int); + method public static deprecated android.view.MotionEvent obtain(long, long, int, int, int[], android.view.MotionEvent.PointerCoords[], int, float, float, int, int, int, int); method public static android.view.MotionEvent obtain(long, long, int, float, float, float, float, int, float, float, int, int); method public static deprecated android.view.MotionEvent obtain(long, long, int, int, float, float, float, float, int, float, float, int, int); method public static android.view.MotionEvent obtain(long, long, int, float, float, int); @@ -20782,6 +20787,7 @@ package android.view { field public static final int ACTION_SCROLL = 8; // 0x8 field public static final int ACTION_UP = 1; // 0x1 field public static final int AXIS_BRAKE = 23; // 0x17 + field public static final int AXIS_DISTANCE = 24; // 0x18 field public static final int AXIS_GAS = 22; // 0x16 field public static final int AXIS_GENERIC_1 = 32; // 0x20 field public static final int AXIS_GENERIC_10 = 41; // 0x29 @@ -20821,12 +20827,25 @@ package android.view { field public static final int AXIS_X = 0; // 0x0 field public static final int AXIS_Y = 1; // 0x1 field public static final int AXIS_Z = 11; // 0xb + field public static final int BUTTON_BACK = 8; // 0x8 + field public static final int BUTTON_ERASER = 32; // 0x20 + field public static final int BUTTON_FORWARD = 16; // 0x10 + field public static final int BUTTON_PRIMARY = 1; // 0x1 + field public static final int BUTTON_SECONDARY = 2; // 0x2 + field public static final int BUTTON_TERTIARY = 4; // 0x4 field public static final android.os.Parcelable.Creator CREATOR; field public static final int EDGE_BOTTOM = 2; // 0x2 field public static final int EDGE_LEFT = 4; // 0x4 field public static final int EDGE_RIGHT = 8; // 0x8 field public static final int EDGE_TOP = 1; // 0x1 field public static final int FLAG_WINDOW_IS_OBSCURED = 1; // 0x1 + field public static final int INVALID_POINTER_ID = -1; // 0xffffffff + field public static final int TOOL_TYPE_FINGER = 1; // 0x1 + field public static final int TOOL_TYPE_INDIRECT_FINGER = 4; // 0x4 + field public static final int TOOL_TYPE_INDIRECT_STYLUS = 5; // 0x5 + field public static final int TOOL_TYPE_MOUSE = 3; // 0x3 + field public static final int TOOL_TYPE_STYLUS = 2; // 0x2 + field public static final int TOOL_TYPE_UNKNOWN = 0; // 0x0 } public static final class MotionEvent.PointerCoords { @@ -20847,6 +20866,15 @@ package android.view { field public float y; } + public static final class MotionEvent.PointerProperties { + ctor public MotionEvent.PointerProperties(); + ctor public MotionEvent.PointerProperties(android.view.MotionEvent.PointerProperties); + method public void clear(); + method public void copyFrom(android.view.MotionEvent.PointerProperties); + field public int id; + field public int toolType; + } + public abstract class OrientationEventListener { ctor public OrientationEventListener(android.content.Context); ctor public OrientationEventListener(android.content.Context, int); diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java index 343242e..7159260 100644 --- a/core/java/android/inputmethodservice/SoftInputWindow.java +++ b/core/java/android/inputmethodservice/SoftInputWindow.java @@ -73,8 +73,17 @@ class SoftInputWindow extends Dialog { @Override public boolean dispatchTouchEvent(MotionEvent ev) { getWindow().getDecorView().getHitRect(mBounds); - final MotionEvent event = clipMotionEvent(ev, mBounds); - return super.dispatchTouchEvent(event); + + if (ev.isWithinBoundsNoHistory(mBounds.left, mBounds.top, + mBounds.right - 1, mBounds.bottom - 1)) { + return super.dispatchTouchEvent(ev); + } else { + MotionEvent temp = ev.clampNoHistory(mBounds.left, mBounds.top, + mBounds.right - 1, mBounds.bottom - 1); + boolean handled = super.dispatchTouchEvent(temp); + temp.recycle(); + return handled; + } } /** @@ -163,48 +172,4 @@ class SoftInputWindow extends Dialog { WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_DIM_BEHIND); } - - private static MotionEvent clipMotionEvent(MotionEvent me, Rect bounds) { - final int pointerCount = me.getPointerCount(); - boolean shouldClip = false; - for (int pointerIndex = 0; pointerIndex < pointerCount; pointerIndex++) { - final int x = (int)me.getX(pointerIndex); - final int y = (int)me.getY(pointerIndex); - if (!bounds.contains(x, y)) { - shouldClip = true; - break; - } - } - if (!shouldClip) - return me; - - if (pointerCount == 1) { - final int x = (int)me.getX(); - final int y = (int)me.getY(); - me.setLocation( - Math.max(bounds.left, Math.min(x, bounds.right - 1)), - Math.max(bounds.top, Math.min(y, bounds.bottom - 1))); - return me; - } - - final int[] pointerIds = new int[pointerCount]; - final MotionEvent.PointerCoords[] pointerCoords = - new MotionEvent.PointerCoords[pointerCount]; - for (int pointerIndex = 0; pointerIndex < pointerCount; pointerIndex++) { - pointerIds[pointerIndex] = me.getPointerId(pointerIndex); - final MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords(); - me.getPointerCoords(pointerIndex, coords); - pointerCoords[pointerIndex] = coords; - final int x = (int)coords.x; - final int y = (int)coords.y; - if (!bounds.contains(x, y)) { - coords.x = Math.max(bounds.left, Math.min(x, bounds.right - 1)); - coords.y = Math.max(bounds.top, Math.min(y, bounds.bottom - 1)); - } - } - return MotionEvent.obtain( - me.getDownTime(), me.getEventTime(), me.getAction(), pointerCount, pointerIds, - pointerCoords, me.getMetaState(), me.getXPrecision(), me.getYPrecision(), - me.getDeviceId(), me.getEdgeFlags(), me.getSource(), me.getFlags()); - } } diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java index 8cb68f9..bfc7c31 100755 --- a/core/java/android/view/InputDevice.java +++ b/core/java/android/view/InputDevice.java @@ -153,7 +153,14 @@ public final class InputDevice implements Parcelable { * @see #SOURCE_CLASS_POINTER */ public static final int SOURCE_MOUSE = 0x00002000 | SOURCE_CLASS_POINTER; - + + /** + * The input source is a stylus pointing device. + * + * @see #SOURCE_CLASS_POINTER + */ + public static final int SOURCE_STYLUS = 0x00004000 | SOURCE_CLASS_POINTER; + /** * The input source is a trackball. * @@ -585,6 +592,7 @@ public final class InputDevice implements Parcelable { appendSourceDescriptionIfApplicable(description, SOURCE_DPAD, "dpad"); appendSourceDescriptionIfApplicable(description, SOURCE_TOUCHSCREEN, "touchscreen"); appendSourceDescriptionIfApplicable(description, SOURCE_MOUSE, "mouse"); + appendSourceDescriptionIfApplicable(description, SOURCE_STYLUS, "stylus"); appendSourceDescriptionIfApplicable(description, SOURCE_TRACKBALL, "trackball"); appendSourceDescriptionIfApplicable(description, SOURCE_TOUCHPAD, "touchpad"); appendSourceDescriptionIfApplicable(description, SOURCE_JOYSTICK, "joystick"); diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index 13d8809..5dbda90 100755 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -2672,15 +2672,22 @@ public class KeyEvent extends InputEvent implements Parcelable { @Override public String toString() { - return "KeyEvent{action=" + actionToString(mAction) - + " keycode=" + keyCodeToString(mKeyCode) - + " scancode=" + mScanCode - + " metaState=" + metaStateToString(mMetaState) - + " flags=0x" + Integer.toHexString(mFlags) - + " repeat=" + mRepeatCount - + " device=" + mDeviceId - + " source=0x" + Integer.toHexString(mSource) - + "}"; + StringBuilder msg = new StringBuilder(); + msg.append("KeyEvent { action=").append(actionToString(mAction)); + msg.append(", keyCode=").append(keyCodeToString(mKeyCode)); + msg.append(", scanCode=").append(mScanCode); + if (mCharacters != null) { + msg.append(", characters=\"").append(mCharacters).append("\""); + } + msg.append(", metaState=").append(metaStateToString(mMetaState)); + msg.append(", flags=0x").append(Integer.toHexString(mFlags)); + msg.append(", repeatCount=").append(mRepeatCount); + msg.append(", eventTime=").append(mEventTime); + msg.append(", downTime=").append(mDownTime); + msg.append(", deviceId=").append(mDeviceId); + msg.append(", source=0x").append(Integer.toHexString(mSource)); + msg.append(" }"); + return msg.toString(); } /** diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 7611b08..82fd581 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -23,53 +23,60 @@ import android.os.SystemClock; import android.util.SparseArray; /** - * Object used to report movement (mouse, pen, finger, trackball) events. This - * class may hold either absolute or relative movements, depending on what - * it is being used for. + * Object used to report movement (mouse, pen, finger, trackball) events. + * Motion events may hold either absolute or relative movements and other data, + * depending on the type of device. + * + * <h3>Overview</h3> * <p> - * On pointing devices with source class {@link InputDevice#SOURCE_CLASS_POINTER} - * such as touch screens, the pointer coordinates specify absolute - * positions such as view X/Y coordinates. Each complete gesture is represented - * by a sequence of motion events with actions that describe pointer state transitions - * and movements. A gesture starts with a motion event with {@link #ACTION_DOWN} - * that provides the location of the first pointer down. As each additional - * pointer that goes down or up, the framework will generate a motion event with - * {@link #ACTION_POINTER_DOWN} or {@link #ACTION_POINTER_UP} accordingly. - * Pointer movements are described by motion events with {@link #ACTION_MOVE}. - * Finally, a gesture end either when the final pointer goes up as represented - * by a motion event with {@link #ACTION_UP} or when gesture is canceled - * with {@link #ACTION_CANCEL}. + * Motion events describe movements in terms of an action code and a set of axis values. + * The action code specifies the state change that occurred such as a pointer going + * down or up. The axis values describe the position and other movement properties. * </p><p> - * Some pointing devices such as mice may support vertical and/or horizontal scrolling. - * A scroll event is reported as a generic motion event with {@link #ACTION_SCROLL} that - * includes the relative scroll offset in the {@link #AXIS_VSCROLL} and - * {@link #AXIS_HSCROLL} axes. See {@link #getAxisValue(int)} for information - * about retrieving these additional axes. + * For example, when the user first touches the screen, the system delivers a touch + * event to the appropriate {@link View} with the action code {@link #ACTION_DOWN} + * and a set of axis values that include the X and Y coordinates of the touch and + * information about the pressure, size and orientation of the contact area. * </p><p> - * On trackball devices with source class {@link InputDevice#SOURCE_CLASS_TRACKBALL}, - * the pointer coordinates specify relative movements as X/Y deltas. - * A trackball gesture consists of a sequence of movements described by motion - * events with {@link #ACTION_MOVE} interspersed with occasional {@link #ACTION_DOWN} - * or {@link #ACTION_UP} motion events when the trackball button is pressed or released. + * Some devices can report multiple movement traces at the same time. Multi-touch + * screens emit one movement trace for each finger. The individual fingers or + * other objects that generate movement traces are referred to as <em>pointers</em>. + * Motion events contain information about all of the pointers that are currently active + * even if some of them have not moved since the last event was delivered. * </p><p> - * On joystick devices with source class {@link InputDevice#SOURCE_CLASS_JOYSTICK}, - * the pointer coordinates specify the absolute position of the joystick axes. - * The joystick axis values are normalized to a range of -1.0 to 1.0 where 0.0 corresponds - * to the center position. More information about the set of available axes and the - * range of motion can be obtained using {@link InputDevice#getMotionRange}. - * Some common joystick axes are {@link #AXIS_X}, {@link #AXIS_Y}, - * {@link #AXIS_HAT_X}, {@link #AXIS_HAT_Y}, {@link #AXIS_Z} and {@link #AXIS_RZ}. - * </p><p> - * Motion events always report movements for all pointers at once. The number - * of pointers only ever changes by one as individual pointers go up and down, + * The number of pointers only ever changes by one as individual pointers go up and down, * except when the gesture is canceled. * </p><p> - * The order in which individual pointers appear within a motion event can change - * from one event to the next. Use the {@link #getPointerId(int)} method to obtain a - * pointer id to track pointers across motion events in a gesture. Then for - * successive motion events, use the {@link #findPointerIndex(int)} method to obtain - * the pointer index for a given pointer id in that motion event. + * Each pointer has a unique id that is assigned when it first goes down + * (indicated by {@link #ACTION_DOWN} or {@link #ACTION_POINTER_DOWN}). A pointer id + * remains valid until the pointer eventually goes up (indicated by {@link #ACTION_UP} + * or {@link #ACTION_POINTER_UP}) or when the gesture is canceled (indicated by + * {@link #ACTION_CANCEL}). + * </p><p> + * The MotionEvent class provides many methods to query the position and other properties of + * pointers, such as {@link #getX(int)}, {@link #getY(int)}, {@link #getAxisValue}, + * {@link #getPointerId(int)}, {@link #getToolType(int)}, and many others. Most of these + * methods accept the pointer index as a parameter rather than the pointer id. + * The pointer index of each pointer in the event ranges from 0 to one less than the value + * returned by {@link #getPointerCount()}. * </p><p> + * The order in which individual pointers appear within a motion event is undefined. + * Thus the pointer index of a pointer can change from one event to the next but + * the pointer id of a pointer is guaranteed to remain constant as long as the pointer + * remains active. Use the {@link #getPointerId(int)} method to obtain the + * pointer id of a pointer to track it across all subsequent motion events in a gesture. + * Then for successive motion events, use the {@link #findPointerIndex(int)} method + * to obtain the pointer index for a given pointer id in that motion event. + * </p><p> + * Mouse and stylus buttons can be retrieved using {@link #getButtonState()}. It is a + * good idea to check the button state while handling {@link #ACTION_DOWN} as part + * of a touch event. The application may choose to perform some different action + * if the touch event starts due to a secondary button click, such as presenting a + * context menu. + * </p> + * + * <h3>Batching</h3> + * <p> * For efficiency, motion events with {@link #ACTION_MOVE} may batch together * multiple movement samples within a single object. The most current * pointer coordinates are available using {@link #getX(int)} and {@link #getY(int)}. @@ -98,42 +105,104 @@ import android.util.SparseArray; * ev.getPointerId(p), ev.getX(p), ev.getY(p)); * } * } - * </code></pre></p><p> - * In general, the framework cannot guarantee that the motion events it delivers - * to a view always constitute a complete motion sequences since some events may be dropped - * or modified by containing views before they are delivered. The view implementation - * should be prepared to handle {@link #ACTION_CANCEL} and should tolerate anomalous - * situations such as receiving a new {@link #ACTION_DOWN} without first having - * received an {@link #ACTION_UP} for the prior gesture. + * </code></pre></p> + * + * <h3>Device Types</h3> + * <p> + * The interpretation of the contents of a MotionEvent varies significantly depending + * on the source class of the device. + * </p><p> + * On pointing devices with source class {@link InputDevice#SOURCE_CLASS_POINTER} + * such as touch screens, the pointer coordinates specify absolute + * positions such as view X/Y coordinates. Each complete gesture is represented + * by a sequence of motion events with actions that describe pointer state transitions + * and movements. A gesture starts with a motion event with {@link #ACTION_DOWN} + * that provides the location of the first pointer down. As each additional + * pointer that goes down or up, the framework will generate a motion event with + * {@link #ACTION_POINTER_DOWN} or {@link #ACTION_POINTER_UP} accordingly. + * Pointer movements are described by motion events with {@link #ACTION_MOVE}. + * Finally, a gesture end either when the final pointer goes up as represented + * by a motion event with {@link #ACTION_UP} or when gesture is canceled + * with {@link #ACTION_CANCEL}. + * </p><p> + * Some pointing devices such as mice may support vertical and/or horizontal scrolling. + * A scroll event is reported as a generic motion event with {@link #ACTION_SCROLL} that + * includes the relative scroll offset in the {@link #AXIS_VSCROLL} and + * {@link #AXIS_HSCROLL} axes. See {@link #getAxisValue(int)} for information + * about retrieving these additional axes. + * </p><p> + * On trackball devices with source class {@link InputDevice#SOURCE_CLASS_TRACKBALL}, + * the pointer coordinates specify relative movements as X/Y deltas. + * A trackball gesture consists of a sequence of movements described by motion + * events with {@link #ACTION_MOVE} interspersed with occasional {@link #ACTION_DOWN} + * or {@link #ACTION_UP} motion events when the trackball button is pressed or released. + * </p><p> + * On joystick devices with source class {@link InputDevice#SOURCE_CLASS_JOYSTICK}, + * the pointer coordinates specify the absolute position of the joystick axes. + * The joystick axis values are normalized to a range of -1.0 to 1.0 where 0.0 corresponds + * to the center position. More information about the set of available axes and the + * range of motion can be obtained using {@link InputDevice#getMotionRange}. + * Some common joystick axes are {@link #AXIS_X}, {@link #AXIS_Y}, + * {@link #AXIS_HAT_X}, {@link #AXIS_HAT_Y}, {@link #AXIS_Z} and {@link #AXIS_RZ}. * </p><p> * Refer to {@link InputDevice} for more information about how different kinds of * input devices and sources represent pointer coordinates. * </p> + * + * <h3>Consistency Guarantees</h3> + * <p> + * Motion events are always delivered to views as a consistent stream of events. + * What constitutes a consistent stream varies depending on the type of device. + * For touch events, consistency implies that pointers go down one at a time, + * move around as a group and then go up one at a time or are canceled. + * </p><p> + * While the framework tries to deliver consistent streams of motion events to + * views, it cannot guarantee it. Some events may be dropped or modified by + * containing views in the application before they are delivered thereby making + * the stream of events inconsistent. Views should always be prepared to + * handle {@link #ACTION_CANCEL} and should tolerate anomalous + * situations such as receiving a new {@link #ACTION_DOWN} without first having + * received an {@link #ACTION_UP} for the prior gesture. + * </p> */ public final class MotionEvent extends InputEvent implements Parcelable { private static final long NS_PER_MS = 1000000; private static final boolean TRACK_RECYCLED_LOCATION = false; - + + /** + * An invalid pointer id. + * + * This value (-1) can be used as a placeholder to indicate that a pointer id + * has not been assigned or is not available. It cannot appear as + * a pointer id inside a {@link MotionEvent}. + */ + public static final int INVALID_POINTER_ID = -1; + /** * Bit mask of the parts of the action code that are the action itself. */ public static final int ACTION_MASK = 0xff; /** - * Constant for {@link #getAction}: A pressed gesture has started, the + * Constant for {@link #getActionMasked}: A pressed gesture has started, the * motion contains the initial starting location. + * <p> + * This is also a good time to check the button state to distinguish + * secondary and tertiary button clicks and handle them appropriately. + * Use {@link #getButtonState} to retrieve the button state. + * </p> */ public static final int ACTION_DOWN = 0; /** - * Constant for {@link #getAction}: A pressed gesture has finished, the + * Constant for {@link #getActionMasked}: A pressed gesture has finished, the * motion contains the final release location as well as any intermediate * points since the last down or move event. */ public static final int ACTION_UP = 1; /** - * Constant for {@link #getAction}: A change has happened during a + * Constant for {@link #getActionMasked}: A change has happened during a * press gesture (between {@link #ACTION_DOWN} and {@link #ACTION_UP}). * The motion contains the most recent point, as well as any intermediate * points since the last down or move event. @@ -141,33 +210,43 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int ACTION_MOVE = 2; /** - * Constant for {@link #getAction}: The current gesture has been aborted. + * Constant for {@link #getActionMasked}: The current gesture has been aborted. * You will not receive any more points in it. You should treat this as * an up event, but not perform any action that you normally would. */ public static final int ACTION_CANCEL = 3; /** - * Constant for {@link #getAction}: A movement has happened outside of the + * Constant for {@link #getActionMasked}: A movement has happened outside of the * normal bounds of the UI element. This does not provide a full gesture, * but only the initial location of the movement/touch. */ public static final int ACTION_OUTSIDE = 4; /** - * A non-primary pointer has gone down. The bits in - * {@link #ACTION_POINTER_ID_MASK} indicate which pointer changed. + * Constant for {@link #getActionMasked}: A non-primary pointer has gone down. + * <p> + * Use {@link #getActionIndex} to retrieve the index of the pointer that changed. + * </p><p> + * The index is encoded in the {@link #ACTION_POINTER_INDEX_MASK} bits of the + * unmasked action returned by {@link #getAction}. + * </p> */ public static final int ACTION_POINTER_DOWN = 5; /** - * A non-primary pointer has gone up. The bits in - * {@link #ACTION_POINTER_ID_MASK} indicate which pointer changed. + * Constant for {@link #getActionMasked}: A non-primary pointer has gone up. + * <p> + * Use {@link #getActionIndex} to retrieve the index of the pointer that changed. + * </p><p> + * The index is encoded in the {@link #ACTION_POINTER_INDEX_MASK} bits of the + * unmasked action returned by {@link #getAction}. + * </p> */ public static final int ACTION_POINTER_UP = 6; /** - * Constant for {@link #getAction}: A change happened but the pointer + * Constant for {@link #getActionMasked}: A change happened but the pointer * is not down (unlike {@link #ACTION_MOVE}). The motion contains the most * recent point, as well as any intermediate points since the last * hover move event. @@ -182,14 +261,14 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int ACTION_HOVER_MOVE = 7; /** - * Constant for {@link #getAction}: The motion event contains relative + * Constant for {@link #getActionMasked}: The motion event contains relative * vertical and/or horizontal scroll offsets. Use {@link #getAxisValue(int)} * to retrieve the information from {@link #AXIS_VSCROLL} and {@link #AXIS_HSCROLL}. * The pointer may or may not be down when this event is dispatched. - * <p></p> + * <p> * This action is always delivered to the window or view under the pointer, which * may not be the window or view currently touched. - * <p> + * </p><p> * This action is not a touch event so it is delivered to * {@link View#onGenericMotionEvent(MotionEvent)} rather than * {@link View#onTouchEvent(MotionEvent)}. @@ -198,7 +277,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int ACTION_SCROLL = 8; /** - * Constant for {@link #getAction}: The pointer is not down but has entered the + * Constant for {@link #getActionMasked}: The pointer is not down but has entered the * boundaries of a window or view. * <p> * This action is always delivered to the window or view under the pointer. @@ -211,7 +290,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int ACTION_HOVER_ENTER = 9; /** - * Constant for {@link #getAction}: The pointer is not down but has exited the + * Constant for {@link #getActionMasked}: The pointer is not down but has exited the * boundaries of a window or view. * <p> * This action is always delivered to the window or view that was previously under the pointer. @@ -230,15 +309,19 @@ public final class MotionEvent extends InputEvent implements Parcelable { * index where the data for the pointer going up or down can be found; you can * get its identifier with {@link #getPointerId(int)} and the actual * data with {@link #getX(int)} etc. + * + * @see #getActionIndex */ public static final int ACTION_POINTER_INDEX_MASK = 0xff00; /** * Bit shift for the action bits holding the pointer index as * defined by {@link #ACTION_POINTER_INDEX_MASK}. + * + * @see #getActionIndex */ public static final int ACTION_POINTER_INDEX_SHIFT = 8; - + /** * @deprecated Use {@link #ACTION_POINTER_INDEX_MASK} to retrieve the * data index associated with {@link #ACTION_POINTER_DOWN}. @@ -339,7 +422,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int EDGE_RIGHT = 0x00000008; /** - * Constant used to identify the X axis of a motion event. + * Axis constant: X axis of a motion event. * <p> * <ul> * <li>For a touch screen, reports the absolute X screen position of the center of @@ -364,7 +447,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_X = 0; /** - * Constant used to identify the Y axis of a motion event. + * Axis constant: Y axis of a motion event. * <p> * <ul> * <li>For a touch screen, reports the absolute Y screen position of the center of @@ -389,7 +472,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_Y = 1; /** - * Constant used to identify the Pressure axis of a motion event. + * Axis constant: Pressure axis of a motion event. * <p> * <ul> * <li>For a touch screen or touch pad, reports the approximate pressure applied to the surface @@ -411,7 +494,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_PRESSURE = 2; /** - * Constant used to identify the Size axis of a motion event. + * Axis constant: Size axis of a motion event. * <p> * <ul> * <li>For a touch screen or touch pad, reports the approximate size of the contact area in @@ -431,7 +514,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_SIZE = 3; /** - * Constant used to identify the TouchMajor axis of a motion event. + * Axis constant: TouchMajor axis of a motion event. * <p> * <ul> * <li>For a touch screen, reports the length of the major axis of an ellipse that @@ -452,7 +535,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_TOUCH_MAJOR = 4; /** - * Constant used to identify the TouchMinor axis of a motion event. + * Axis constant: TouchMinor axis of a motion event. * <p> * <ul> * <li>For a touch screen, reports the length of the minor axis of an ellipse that @@ -475,7 +558,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_TOUCH_MINOR = 5; /** - * Constant used to identify the ToolMajor axis of a motion event. + * Axis constant: ToolMajor axis of a motion event. * <p> * <ul> * <li>For a touch screen, reports the length of the major axis of an ellipse that @@ -500,7 +583,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_TOOL_MAJOR = 6; /** - * Constant used to identify the ToolMinor axis of a motion event. + * Axis constant: ToolMinor axis of a motion event. * <p> * <ul> * <li>For a touch screen, reports the length of the minor axis of an ellipse that @@ -525,7 +608,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_TOOL_MINOR = 7; /** - * Constant used to identify the Orientation axis of a motion event. + * Axis constant: Orientation axis of a motion event. * <p> * <ul> * <li>For a touch screen or touch pad, reports the orientation of the finger @@ -547,7 +630,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_ORIENTATION = 8; /** - * Constant used to identify the Vertical Scroll axis of a motion event. + * Axis constant: Vertical Scroll axis of a motion event. * <p> * <ul> * <li>For a mouse, reports the relative movement of the vertical scroll wheel. @@ -565,7 +648,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_VSCROLL = 9; /** - * Constant used to identify the Horizontal Scroll axis of a motion event. + * Axis constant: Horizontal Scroll axis of a motion event. * <p> * <ul> * <li>For a mouse, reports the relative movement of the horizontal scroll wheel. @@ -583,7 +666,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_HSCROLL = 10; /** - * Constant used to identify the Z axis of a motion event. + * Axis constant: Z axis of a motion event. * <p> * <ul> * <li>For a joystick, reports the absolute Z position of the joystick. @@ -601,7 +684,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_Z = 11; /** - * Constant used to identify the X Rotation axis of a motion event. + * Axis constant: X Rotation axis of a motion event. * <p> * <ul> * <li>For a joystick, reports the absolute rotation angle about the X axis. @@ -617,7 +700,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_RX = 12; /** - * Constant used to identify the Y Rotation axis of a motion event. + * Axis constant: Y Rotation axis of a motion event. * <p> * <ul> * <li>For a joystick, reports the absolute rotation angle about the Y axis. @@ -633,7 +716,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_RY = 13; /** - * Constant used to identify the Z Rotation axis of a motion event. + * Axis constant: Z Rotation axis of a motion event. * <p> * <ul> * <li>For a joystick, reports the absolute rotation angle about the Z axis. @@ -651,7 +734,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_RZ = 14; /** - * Constant used to identify the Hat X axis of a motion event. + * Axis constant: Hat X axis of a motion event. * <p> * <ul> * <li>For a joystick, reports the absolute X position of the directional hat control. @@ -667,7 +750,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_HAT_X = 15; /** - * Constant used to identify the Hat Y axis of a motion event. + * Axis constant: Hat Y axis of a motion event. * <p> * <ul> * <li>For a joystick, reports the absolute Y position of the directional hat control. @@ -683,7 +766,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_HAT_Y = 16; /** - * Constant used to identify the Left Trigger axis of a motion event. + * Axis constant: Left Trigger axis of a motion event. * <p> * <ul> * <li>For a joystick, reports the absolute position of the left trigger control. @@ -699,7 +782,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_LTRIGGER = 17; /** - * Constant used to identify the Right Trigger axis of a motion event. + * Axis constant: Right Trigger axis of a motion event. * <p> * <ul> * <li>For a joystick, reports the absolute position of the right trigger control. @@ -715,7 +798,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_RTRIGGER = 18; /** - * Constant used to identify the Throttle axis of a motion event. + * Axis constant: Throttle axis of a motion event. * <p> * <ul> * <li>For a joystick, reports the absolute position of the throttle control. @@ -731,7 +814,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_THROTTLE = 19; /** - * Constant used to identify the Rudder axis of a motion event. + * Axis constant: Rudder axis of a motion event. * <p> * <ul> * <li>For a joystick, reports the absolute position of the rudder control. @@ -747,7 +830,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_RUDDER = 20; /** - * Constant used to identify the Wheel axis of a motion event. + * Axis constant: Wheel axis of a motion event. * <p> * <ul> * <li>For a joystick, reports the absolute position of the steering wheel control. @@ -763,7 +846,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_WHEEL = 21; /** - * Constant used to identify the Gas axis of a motion event. + * Axis constant: Gas axis of a motion event. * <p> * <ul> * <li>For a joystick, reports the absolute position of the gas (accelerator) control. @@ -780,7 +863,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_GAS = 22; /** - * Constant used to identify the Brake axis of a motion event. + * Axis constant: Brake axis of a motion event. * <p> * <ul> * <li>For a joystick, reports the absolute position of the brake control. @@ -796,7 +879,24 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_BRAKE = 23; /** - * Constant used to identify the Generic 1 axis of a motion event. + * Axis constant: Distance axis of a motion event. + * <p> + * <ul> + * <li>For a stylus, reports the distance of the stylus from the screen. + * The value is normalized to a range from 0.0 (direct contact) to 1.0 (furthest measurable + * distance). + * </ul> + * </p> + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_DISTANCE = 24; + + /** + * Axis constant: Generic 1 axis of a motion event. * The interpretation of a generic axis is device-specific. * * @see #getAxisValue(int, int) @@ -807,7 +907,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_GENERIC_1 = 32; /** - * Constant used to identify the Generic 2 axis of a motion event. + * Axis constant: Generic 2 axis of a motion event. * The interpretation of a generic axis is device-specific. * * @see #getAxisValue(int, int) @@ -818,7 +918,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_GENERIC_2 = 33; /** - * Constant used to identify the Generic 3 axis of a motion event. + * Axis constant: Generic 3 axis of a motion event. * The interpretation of a generic axis is device-specific. * * @see #getAxisValue(int, int) @@ -829,7 +929,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_GENERIC_3 = 34; /** - * Constant used to identify the Generic 4 axis of a motion event. + * Axis constant: Generic 4 axis of a motion event. * The interpretation of a generic axis is device-specific. * * @see #getAxisValue(int, int) @@ -840,7 +940,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_GENERIC_4 = 35; /** - * Constant used to identify the Generic 5 axis of a motion event. + * Axis constant: Generic 5 axis of a motion event. * The interpretation of a generic axis is device-specific. * * @see #getAxisValue(int, int) @@ -851,7 +951,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_GENERIC_5 = 36; /** - * Constant used to identify the Generic 6 axis of a motion event. + * Axis constant: Generic 6 axis of a motion event. * The interpretation of a generic axis is device-specific. * * @see #getAxisValue(int, int) @@ -862,7 +962,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_GENERIC_6 = 37; /** - * Constant used to identify the Generic 7 axis of a motion event. + * Axis constant: Generic 7 axis of a motion event. * The interpretation of a generic axis is device-specific. * * @see #getAxisValue(int, int) @@ -873,7 +973,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_GENERIC_7 = 38; /** - * Constant used to identify the Generic 8 axis of a motion event. + * Axis constant: Generic 8 axis of a motion event. * The interpretation of a generic axis is device-specific. * * @see #getAxisValue(int, int) @@ -884,7 +984,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_GENERIC_8 = 39; /** - * Constant used to identify the Generic 9 axis of a motion event. + * Axis constant: Generic 9 axis of a motion event. * The interpretation of a generic axis is device-specific. * * @see #getAxisValue(int, int) @@ -895,7 +995,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_GENERIC_9 = 40; /** - * Constant used to identify the Generic 10 axis of a motion event. + * Axis constant: Generic 10 axis of a motion event. * The interpretation of a generic axis is device-specific. * * @see #getAxisValue(int, int) @@ -906,7 +1006,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_GENERIC_10 = 41; /** - * Constant used to identify the Generic 11 axis of a motion event. + * Axis constant: Generic 11 axis of a motion event. * The interpretation of a generic axis is device-specific. * * @see #getAxisValue(int, int) @@ -917,7 +1017,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_GENERIC_11 = 42; /** - * Constant used to identify the Generic 12 axis of a motion event. + * Axis constant: Generic 12 axis of a motion event. * The interpretation of a generic axis is device-specific. * * @see #getAxisValue(int, int) @@ -928,7 +1028,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_GENERIC_12 = 43; /** - * Constant used to identify the Generic 13 axis of a motion event. + * Axis constant: Generic 13 axis of a motion event. * The interpretation of a generic axis is device-specific. * * @see #getAxisValue(int, int) @@ -939,7 +1039,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_GENERIC_13 = 44; /** - * Constant used to identify the Generic 14 axis of a motion event. + * Axis constant: Generic 14 axis of a motion event. * The interpretation of a generic axis is device-specific. * * @see #getAxisValue(int, int) @@ -950,7 +1050,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_GENERIC_14 = 45; /** - * Constant used to identify the Generic 15 axis of a motion event. + * Axis constant: Generic 15 axis of a motion event. * The interpretation of a generic axis is device-specific. * * @see #getAxisValue(int, int) @@ -961,7 +1061,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_GENERIC_15 = 46; /** - * Constant used to identify the Generic 16 axis of a motion event. + * Axis constant: Generic 16 axis of a motion event. * The interpretation of a generic axis is device-specific. * * @see #getAxisValue(int, int) @@ -977,7 +1077,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { // Symbolic names of all axes. private static final SparseArray<String> AXIS_SYMBOLIC_NAMES = new SparseArray<String>(); - private static void populateAxisSymbolicNames() { + static { SparseArray<String> names = AXIS_SYMBOLIC_NAMES; names.append(AXIS_X, "AXIS_X"); names.append(AXIS_Y, "AXIS_Y"); @@ -1003,6 +1103,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { names.append(AXIS_WHEEL, "AXIS_WHEEL"); names.append(AXIS_GAS, "AXIS_GAS"); names.append(AXIS_BRAKE, "AXIS_BRAKE"); + names.append(AXIS_DISTANCE, "AXIS_DISTANCE"); names.append(AXIS_GENERIC_1, "AXIS_GENERIC_1"); names.append(AXIS_GENERIC_2, "AXIS_GENERIC_2"); names.append(AXIS_GENERIC_3, "AXIS_GENERIC_3"); @@ -1021,8 +1122,169 @@ public final class MotionEvent extends InputEvent implements Parcelable { names.append(AXIS_GENERIC_16, "AXIS_GENERIC_16"); } + /** + * Button constant: Primary button (left mouse button, stylus tip). + * + * @see #getButtonState + */ + public static final int BUTTON_PRIMARY = 1 << 0; + + /** + * Button constant: Secondary button (right mouse button, stylus barrel). + * + * @see #getButtonState + */ + public static final int BUTTON_SECONDARY = 1 << 1; + + /** + * Button constant: Tertiary button (middle mouse button). + * + * @see #getButtonState + */ + public static final int BUTTON_TERTIARY = 1 << 2; + + /** + * Button constant: Back button pressed (mouse back button). + * <p> + * The system may send a {@link KeyEvent#KEYCODE_BACK} key press to the application + * when this button is pressed. + * </p> + * + * @see #getButtonState + */ + public static final int BUTTON_BACK = 1 << 3; + + /** + * Button constant: Forward button pressed (mouse forward button). + * <p> + * The system may send a {@link KeyEvent#KEYCODE_FORWARD} key press to the application + * when this button is pressed. + * </p> + * + * @see #getButtonState + */ + public static final int BUTTON_FORWARD = 1 << 4; + + /** + * Button constant: Eraser button pressed (stylus end). + * + * @see #getButtonState + */ + public static final int BUTTON_ERASER = 1 << 5; + + // NOTE: If you add a new axis here you must also add it to: + // native/include/android/input.h + + // Symbolic names of all button states in bit order from least significant + // to most significant. + private static final String[] BUTTON_SYMBOLIC_NAMES = new String[] { + "BUTTON_PRIMARY", + "BUTTON_SECONDARY", + "BUTTON_TERTIARY", + "BUTTON_BACK", + "BUTTON_FORWARD", + "BUTTON_ERASER", + "0x00000040", + "0x00000080", + "0x00000100", + "0x00000200", + "0x00000400", + "0x00000800", + "0x00001000", + "0x00002000", + "0x00004000", + "0x00008000", + "0x00010000", + "0x00020000", + "0x00040000", + "0x00080000", + "0x00100000", + "0x00200000", + "0x00400000", + "0x00800000", + "0x01000000", + "0x02000000", + "0x04000000", + "0x08000000", + "0x10000000", + "0x20000000", + "0x40000000", + "0x80000000", + }; + + /** + * Tool type constant: Unknown tool type. + * This constant is used when the tool type is not known or is not relevant, + * such as for a trackball or other non-pointing device. + * + * @see #getToolType + */ + public static final int TOOL_TYPE_UNKNOWN = 0; + + /** + * Tool type constant: The tool is a finger directly touching the display. + * + * This is a <em>direct</em> positioning tool. + * + * @see #getToolType + */ + public static final int TOOL_TYPE_FINGER = 1; + + /** + * Tool type constant: The tool is a stylus directly touching the display + * or hovering slightly above it. + * + * This is a <em>direct</em> positioning tool. + * + * @see #getToolType + */ + public static final int TOOL_TYPE_STYLUS = 2; + + /** + * Tool type constant: The tool is a mouse or trackpad that translates + * relative motions into cursor movements on the display. + * + * This is an <em>indirect</em> positioning tool. + * + * @see #getToolType + */ + public static final int TOOL_TYPE_MOUSE = 3; + + /** + * Tool type constant: The tool is a finger on a touch pad that is not + * directly attached to the display. Finger movements on the touch pad + * may be translated into touches on the display, possibly with visual feedback. + * + * This is an <em>indirect</em> positioning tool. + * + * @see #getToolType + */ + public static final int TOOL_TYPE_INDIRECT_FINGER = 4; + + /** + * Tool type constant: The tool is a stylus on a digitizer tablet that is not + * attached to the display. Stylus movements on the digitizer may be translated + * into touches on the display, possibly with visual feedback. + * + * This is an <em>indirect</em> positioning tool. + * + * @see #getToolType + */ + public static final int TOOL_TYPE_INDIRECT_STYLUS = 5; + + // NOTE: If you add a new tool type here you must also add it to: + // native/include/android/input.h + + // Symbolic names of all tool types. + private static final SparseArray<String> TOOL_TYPE_SYMBOLIC_NAMES = new SparseArray<String>(); static { - populateAxisSymbolicNames(); + SparseArray<String> names = TOOL_TYPE_SYMBOLIC_NAMES; + names.append(TOOL_TYPE_UNKNOWN, "TOOL_TYPE_UNKNOWN"); + names.append(TOOL_TYPE_FINGER, "TOOL_TYPE_FINGER"); + names.append(TOOL_TYPE_STYLUS, "TOOL_TYPE_STYLUS"); + names.append(TOOL_TYPE_MOUSE, "TOOL_TYPE_MOUSE"); + names.append(TOOL_TYPE_INDIRECT_FINGER, "TOOL_TYPE_INDIRECT_FINGER"); + names.append(TOOL_TYPE_INDIRECT_STYLUS, "TOOL_TYPE_INDIRECT_STYLUS"); } // Private value for history pos that obtains the current sample. @@ -1035,10 +1297,23 @@ public final class MotionEvent extends InputEvent implements Parcelable { // Shared temporary objects used when translating coordinates supplied by // the caller into single element PointerCoords and pointer id arrays. - // Must lock gTmpPointerCoords prior to use. - private static final PointerCoords[] gTmpPointerCoords = - new PointerCoords[] { new PointerCoords() }; - private static final int[] gTmpPointerIds = new int[] { 0 /*always 0*/ }; + private static final Object gSharedTempLock = new Object(); + private static PointerCoords[] gSharedTempPointerCoords; + private static PointerProperties[] gSharedTempPointerProperties; + private static int[] gSharedTempPointerIndexMap; + + private static final void ensureSharedTempPointerCapacity(int desiredCapacity) { + if (gSharedTempPointerCoords == null + || gSharedTempPointerCoords.length < desiredCapacity) { + int capacity = gSharedTempPointerCoords != null ? gSharedTempPointerCoords.length : 8; + while (capacity < desiredCapacity) { + capacity *= 2; + } + gSharedTempPointerCoords = PointerCoords.createArray(capacity); + gSharedTempPointerProperties = PointerProperties.createArray(capacity); + gSharedTempPointerIndexMap = new int[capacity]; + } + } // Pointer to the native MotionEvent object that contains the actual data. private int mNativePtr; @@ -1048,10 +1323,11 @@ public final class MotionEvent extends InputEvent implements Parcelable { private boolean mRecycled; private static native int nativeInitialize(int nativePtr, - int deviceId, int source, int action, int flags, int edgeFlags, int metaState, + int deviceId, int source, int action, int flags, int edgeFlags, + int metaState, int buttonState, float xOffset, float yOffset, float xPrecision, float yPrecision, long downTimeNanos, long eventTimeNanos, - int pointerCount, int[] pointerIds, PointerCoords[] pointerCoords); + int pointerCount, PointerProperties[] pointerIds, PointerCoords[] pointerCoords); private static native int nativeCopy(int destNativePtr, int sourceNativePtr, boolean keepHistory); private static native void nativeDispose(int nativePtr); @@ -1069,13 +1345,18 @@ public final class MotionEvent extends InputEvent implements Parcelable { private static native int nativeGetEdgeFlags(int nativePtr); private static native void nativeSetEdgeFlags(int nativePtr, int action); private static native int nativeGetMetaState(int nativePtr); + private static native int nativeGetButtonState(int nativePtr); private static native void nativeOffsetLocation(int nativePtr, float deltaX, float deltaY); + private static native float nativeGetXOffset(int nativePtr); + private static native float nativeGetYOffset(int nativePtr); private static native float nativeGetXPrecision(int nativePtr); private static native float nativeGetYPrecision(int nativePtr); private static native long nativeGetDownTimeNanos(int nativePtr); + private static native void nativeSetDownTimeNanos(int nativePtr, long downTime); private static native int nativeGetPointerCount(int nativePtr); private static native int nativeGetPointerId(int nativePtr, int pointerIndex); + private static native int nativeGetToolType(int nativePtr, int pointerIndex); private static native int nativeFindPointerIndex(int nativePtr, int pointerId); private static native int nativeGetHistorySize(int nativePtr); @@ -1086,6 +1367,8 @@ public final class MotionEvent extends InputEvent implements Parcelable { int axis, int pointerIndex, int historyPos); private static native void nativeGetPointerCoords(int nativePtr, int pointerIndex, int historyPos, PointerCoords outPointerCoords); + private static native void nativeGetPointerProperties(int nativePtr, + int pointerIndex, PointerProperties outPointerProperties); private static native void nativeScale(int nativePtr, float scale); private static native void nativeTransform(int nativePtr, Matrix matrix); @@ -1127,19 +1410,21 @@ public final class MotionEvent extends InputEvent implements Parcelable { /** * Create a new MotionEvent, filling in all of the basic values that * define the motion. - * + * * @param downTime The time (in ms) when the user originally pressed down to start * a stream of position events. This must be obtained from {@link SystemClock#uptimeMillis()}. * @param eventTime The the time (in ms) when this specific event was generated. This * must be obtained from {@link SystemClock#uptimeMillis()}. * @param action The kind of action being performed, such as {@link #ACTION_DOWN}. - * @param pointers The number of points that will be in this event. - * @param pointerIds An array of <em>pointers</em> values providing - * an identifier for each pointer. - * @param pointerCoords An array of <em>pointers</em> values providing + * @param pointerCount The number of pointers that will be in this event. + * @param pointerProperties An array of <em>pointerCount</em> values providing + * a {@link PointerProperties} property object for each pointer, which must + * include the pointer identifier. + * @param pointerCoords An array of <em>pointerCount</em> values providing * a {@link PointerCoords} coordinate object for each pointer. * @param metaState The state of any meta / modifier keys that were in effect when * the event was generated. + * @param buttonState The state of buttons that are pressed. * @param xPrecision The precision of the X coordinate being reported. * @param yPrecision The precision of the Y coordinate being reported. * @param deviceId The id for the device that this event came from. An id of @@ -1151,21 +1436,69 @@ public final class MotionEvent extends InputEvent implements Parcelable { * @param flags The motion event flags. */ static public MotionEvent obtain(long downTime, long eventTime, - int action, int pointers, int[] pointerIds, PointerCoords[] pointerCoords, - int metaState, float xPrecision, float yPrecision, int deviceId, + int action, int pointerCount, PointerProperties[] pointerProperties, + PointerCoords[] pointerCoords, int metaState, int buttonState, + float xPrecision, float yPrecision, int deviceId, int edgeFlags, int source, int flags) { MotionEvent ev = obtain(); ev.mNativePtr = nativeInitialize(ev.mNativePtr, - deviceId, source, action, flags, edgeFlags, metaState, + deviceId, source, action, flags, edgeFlags, metaState, buttonState, 0, 0, xPrecision, yPrecision, downTime * NS_PER_MS, eventTime * NS_PER_MS, - pointers, pointerIds, pointerCoords); + pointerCount, pointerProperties, pointerCoords); return ev; } /** * Create a new MotionEvent, filling in all of the basic values that * define the motion. + * + * @param downTime The time (in ms) when the user originally pressed down to start + * a stream of position events. This must be obtained from {@link SystemClock#uptimeMillis()}. + * @param eventTime The the time (in ms) when this specific event was generated. This + * must be obtained from {@link SystemClock#uptimeMillis()}. + * @param action The kind of action being performed, such as {@link #ACTION_DOWN}. + * @param pointerCount The number of pointers that will be in this event. + * @param pointerIds An array of <em>pointerCount</em> values providing + * an identifier for each pointer. + * @param pointerCoords An array of <em>pointerCount</em> values providing + * a {@link PointerCoords} coordinate object for each pointer. + * @param metaState The state of any meta / modifier keys that were in effect when + * the event was generated. + * @param xPrecision The precision of the X coordinate being reported. + * @param yPrecision The precision of the Y coordinate being reported. + * @param deviceId The id for the device that this event came from. An id of + * zero indicates that the event didn't come from a physical device; other + * numbers are arbitrary and you shouldn't depend on the values. + * @param edgeFlags A bitfield indicating which edges, if any, were touched by this + * MotionEvent. + * @param source The source of this event. + * @param flags The motion event flags. + * + * @deprecated Use {@link #obtain(long, long, int, int, PointerProperties[], PointerCoords[], int, int, float, float, int, int, int, int)} + * instead. + */ + @Deprecated + static public MotionEvent obtain(long downTime, long eventTime, + int action, int pointerCount, int[] pointerIds, PointerCoords[] pointerCoords, + int metaState, float xPrecision, float yPrecision, int deviceId, + int edgeFlags, int source, int flags) { + synchronized (gSharedTempLock) { + ensureSharedTempPointerCapacity(pointerCount); + final PointerProperties[] pp = gSharedTempPointerProperties; + for (int i = 0; i < pointerCount; i++) { + pp[i].clear(); + pp[i].id = pointerIds[i]; + } + return obtain(downTime, eventTime, action, pointerCount, pp, + pointerCoords, metaState, 0, xPrecision, yPrecision, deviceId, + edgeFlags, source, flags); + } + } + + /** + * Create a new MotionEvent, filling in all of the basic values that + * define the motion. * * @param downTime The time (in ms) when the user originally pressed down to start * a stream of position events. This must be obtained from {@link SystemClock#uptimeMillis()}. @@ -1195,20 +1528,25 @@ public final class MotionEvent extends InputEvent implements Parcelable { static public MotionEvent obtain(long downTime, long eventTime, int action, float x, float y, float pressure, float size, int metaState, float xPrecision, float yPrecision, int deviceId, int edgeFlags) { - synchronized (gTmpPointerCoords) { - final PointerCoords pc = gTmpPointerCoords[0]; - pc.clear(); - pc.x = x; - pc.y = y; - pc.pressure = pressure; - pc.size = size; - - MotionEvent ev = obtain(); + MotionEvent ev = obtain(); + synchronized (gSharedTempLock) { + ensureSharedTempPointerCapacity(1); + final PointerProperties[] pp = gSharedTempPointerProperties; + pp[0].clear(); + pp[0].id = 0; + + final PointerCoords pc[] = gSharedTempPointerCoords; + pc[0].clear(); + pc[0].x = x; + pc[0].y = y; + pc[0].pressure = pressure; + pc[0].size = size; + ev.mNativePtr = nativeInitialize(ev.mNativePtr, - deviceId, InputDevice.SOURCE_UNKNOWN, action, 0, edgeFlags, metaState, + deviceId, InputDevice.SOURCE_UNKNOWN, action, 0, edgeFlags, metaState, 0, 0, 0, xPrecision, yPrecision, downTime * NS_PER_MS, eventTime * NS_PER_MS, - 1, gTmpPointerIds, gTmpPointerCoords); + 1, pp, pc); return ev; } } @@ -1222,7 +1560,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { * @param eventTime The the time (in ms) when this specific event was generated. This * must be obtained from {@link SystemClock#uptimeMillis()}. * @param action The kind of action being performed, such as {@link #ACTION_DOWN}. - * @param pointers The number of pointers that are active in this event. + * @param pointerCount The number of pointers that are active in this event. * @param x The X coordinate of this event. * @param y The Y coordinate of this event. * @param pressure The current pressure of this event. The pressure generally @@ -1248,7 +1586,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { */ @Deprecated static public MotionEvent obtain(long downTime, long eventTime, int action, - int pointers, float x, float y, float pressure, float size, int metaState, + int pointerCount, float x, float y, float pressure, float size, int metaState, float xPrecision, float yPrecision, int deviceId, int edgeFlags) { return obtain(downTime, eventTime, action, x, y, pressure, size, metaState, xPrecision, yPrecision, deviceId, edgeFlags); @@ -1444,6 +1782,16 @@ public final class MotionEvent extends InputEvent implements Parcelable { } /** + * Sets the time (in ms) when the user originally pressed down to start + * a stream of position events. + * + * @hide + */ + public final void setDownTime(long downTime) { + nativeSetDownTimeNanos(mNativePtr, downTime * NS_PER_MS); + } + + /** * Returns the time (in ms) when this specific event was generated. */ public final long getEventTime() { @@ -1582,7 +1930,27 @@ public final class MotionEvent extends InputEvent implements Parcelable { public final int getPointerId(int pointerIndex) { return nativeGetPointerId(mNativePtr, pointerIndex); } - + + /** + * Gets the tool type of a pointer for the given pointer index. + * The tool type indicates the type of tool used to make contact such + * as a finger or stylus, if known. + * + * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0 + * (the first pointer that is down) to {@link #getPointerCount()}-1. + * @return The tool type of the pointer. + * + * @see #TOOL_TYPE_UNKNOWN + * @see #TOOL_TYPE_FINGER + * @see #TOOL_TYPE_STYLUS + * @see #TOOL_TYPE_MOUSE + * @see #TOOL_TYPE_INDIRECT_FINGER + * @see #TOOL_TYPE_INDIRECT_STYLUS + */ + public final int getToolType(int pointerIndex) { + return nativeGetToolType(mNativePtr, pointerIndex); + } + /** * Given a pointer identifier, find the index of its data in the event. * @@ -1594,7 +1962,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { public final int findPointerIndex(int pointerId) { return nativeFindPointerIndex(mNativePtr, pointerId); } - + /** * Returns the X coordinate of this event for the given pointer * <em>index</em> (use {@link #getPointerId(int)} to find the pointer @@ -1770,6 +2138,21 @@ public final class MotionEvent extends InputEvent implements Parcelable { } /** + * Populates a {@link PointerProperties} object with pointer properties for + * the specified pointer index. + * + * @param pointerIndex Raw index of pointer to retrieve. Value may be from 0 + * (the first pointer that is down) to {@link #getPointerCount()}-1. + * @param outPointerProperties The pointer properties object to populate. + * + * @see PointerProperties + */ + public final void getPointerProperties(int pointerIndex, + PointerProperties outPointerProperties) { + nativeGetPointerProperties(mNativePtr, pointerIndex, outPointerProperties); + } + + /** * Returns the state of any meta / modifier keys that were in effect when * the event was generated. This is the same values as those * returned by {@link KeyEvent#getMetaState() KeyEvent.getMetaState}. @@ -1784,6 +2167,22 @@ public final class MotionEvent extends InputEvent implements Parcelable { } /** + * Gets the state of all buttons that are pressed such as a mouse or stylus button. + * + * @return The button state. + * + * @see #BUTTON_PRIMARY + * @see #BUTTON_SECONDARY + * @see #BUTTON_TERTIARY + * @see #BUTTON_FORWARD + * @see #BUTTON_BACK + * @see #BUTTON_ERASER + */ + public final int getButtonState() { + return nativeGetButtonState(mNativePtr); + } + + /** * Returns the original raw X coordinate of this event. For touch * events on the screen, this is the original location of the event * on the screen, before it had been adjusted for the containing window @@ -2297,14 +2696,16 @@ public final class MotionEvent extends InputEvent implements Parcelable { */ public final void addBatch(long eventTime, float x, float y, float pressure, float size, int metaState) { - synchronized (gTmpPointerCoords) { - final PointerCoords pc = gTmpPointerCoords[0]; - pc.clear(); - pc.x = x; - pc.y = y; - pc.pressure = pressure; - pc.size = size; - nativeAddBatch(mNativePtr, eventTime * NS_PER_MS, gTmpPointerCoords, metaState); + synchronized (gSharedTempLock) { + ensureSharedTempPointerCapacity(1); + final PointerCoords[] pc = gSharedTempPointerCoords; + pc[0].clear(); + pc[0].x = x; + pc[0].y = y; + pc[0].pressure = pressure; + pc[0].size = size; + + nativeAddBatch(mNativePtr, eventTime * NS_PER_MS, pc, metaState); } } @@ -2323,30 +2724,187 @@ public final class MotionEvent extends InputEvent implements Parcelable { nativeAddBatch(mNativePtr, eventTime * NS_PER_MS, pointerCoords, metaState); } + /** + * Returns true if all points in the motion event are completely within the specified bounds. + * @hide + */ + public final boolean isWithinBoundsNoHistory(float left, float top, + float right, float bottom) { + final int pointerCount = nativeGetPointerCount(mNativePtr); + for (int i = 0; i < pointerCount; i++) { + final float x = nativeGetAxisValue(mNativePtr, AXIS_X, i, HISTORY_CURRENT); + final float y = nativeGetAxisValue(mNativePtr, AXIS_Y, i, HISTORY_CURRENT); + if (x < left || x > right || y < top || y > bottom) { + return false; + } + } + return true; + } + + private static final float clamp(float value, float low, float high) { + if (value < low) { + return low; + } else if (value > high) { + return high; + } + return value; + } + + /** + * Returns a new motion events whose points have been clamped to the specified bounds. + * @hide + */ + public final MotionEvent clampNoHistory(float left, float top, float right, float bottom) { + MotionEvent ev = obtain(); + synchronized (gSharedTempLock) { + final int pointerCount = nativeGetPointerCount(mNativePtr); + + ensureSharedTempPointerCapacity(pointerCount); + final PointerProperties[] pp = gSharedTempPointerProperties; + final PointerCoords[] pc = gSharedTempPointerCoords; + + for (int i = 0; i < pointerCount; i++) { + nativeGetPointerProperties(mNativePtr, i, pp[i]); + nativeGetPointerCoords(mNativePtr, i, HISTORY_CURRENT, pc[i]); + 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), + nativeGetAction(mNativePtr), nativeGetFlags(mNativePtr), + nativeGetEdgeFlags(mNativePtr), nativeGetMetaState(mNativePtr), + nativeGetButtonState(mNativePtr), + nativeGetXOffset(mNativePtr), nativeGetYOffset(mNativePtr), + nativeGetXPrecision(mNativePtr), nativeGetYPrecision(mNativePtr), + nativeGetDownTimeNanos(mNativePtr), + nativeGetEventTimeNanos(mNativePtr, HISTORY_CURRENT), + pointerCount, pp, pc); + return ev; + } + } + + /** + * Gets an integer where each pointer id present in the event is marked as a bit. + * @hide + */ + public final int getPointerIdBits() { + int idBits = 0; + final int pointerCount = nativeGetPointerCount(mNativePtr); + for (int i = 0; i < pointerCount; i++) { + idBits |= 1 << nativeGetPointerId(mNativePtr, i); + } + return idBits; + } + + /** + * Splits a motion event such that it includes only a subset of pointer ids. + * @hide + */ + public final MotionEvent split(int idBits) { + MotionEvent ev = obtain(); + synchronized (gSharedTempLock) { + final int oldPointerCount = nativeGetPointerCount(mNativePtr); + ensureSharedTempPointerCapacity(oldPointerCount); + final PointerProperties[] pp = gSharedTempPointerProperties; + final PointerCoords[] pc = gSharedTempPointerCoords; + final int[] map = gSharedTempPointerIndexMap; + + final int oldAction = nativeGetAction(mNativePtr); + final int oldActionMasked = oldAction & ACTION_MASK; + final int oldActionPointerIndex = (oldAction & ACTION_POINTER_INDEX_MASK) + >> ACTION_POINTER_INDEX_SHIFT; + int newActionPointerIndex = -1; + int newPointerCount = 0; + int newIdBits = 0; + for (int i = 0; i < oldPointerCount; i++) { + nativeGetPointerProperties(mNativePtr, i, pp[newPointerCount]); + final int idBit = 1 << pp[newPointerCount].id; + if ((idBit & idBits) != 0) { + if (i == oldActionPointerIndex) { + newActionPointerIndex = newPointerCount; + } + map[newPointerCount] = i; + newPointerCount += 1; + newIdBits |= idBit; + } + } + + if (newPointerCount == 0) { + throw new IllegalArgumentException("idBits did not match any ids in the event"); + } + + final int newAction; + if (oldActionMasked == ACTION_POINTER_DOWN || oldActionMasked == ACTION_POINTER_UP) { + if (newActionPointerIndex < 0) { + // An unrelated pointer changed. + newAction = ACTION_MOVE; + } else if (newPointerCount == 1) { + // The first/last pointer went down/up. + newAction = oldActionMasked == ACTION_POINTER_DOWN + ? ACTION_DOWN : ACTION_UP; + } else { + // A secondary pointer went down/up. + newAction = oldActionMasked + | (newActionPointerIndex << ACTION_POINTER_INDEX_SHIFT); + } + } else { + // Simple up/down/cancel/move or other motion action. + newAction = oldAction; + } + + final int historySize = nativeGetHistorySize(mNativePtr); + for (int h = 0; h <= historySize; h++) { + final int historyPos = h == historySize ? HISTORY_CURRENT : h; + + for (int i = 0; i < newPointerCount; i++) { + nativeGetPointerCoords(mNativePtr, map[i], historyPos, pc[i]); + } + + final long eventTimeNanos = nativeGetEventTimeNanos(mNativePtr, historyPos); + if (h == 0) { + ev.mNativePtr = nativeInitialize(ev.mNativePtr, + nativeGetDeviceId(mNativePtr), nativeGetSource(mNativePtr), + newAction, nativeGetFlags(mNativePtr), + nativeGetEdgeFlags(mNativePtr), nativeGetMetaState(mNativePtr), + nativeGetButtonState(mNativePtr), + nativeGetXOffset(mNativePtr), nativeGetYOffset(mNativePtr), + nativeGetXPrecision(mNativePtr), nativeGetYPrecision(mNativePtr), + nativeGetDownTimeNanos(mNativePtr), eventTimeNanos, + newPointerCount, pp, pc); + } else { + nativeAddBatch(ev.mNativePtr, eventTimeNanos, pc, 0); + } + } + return ev; + } + } + @Override public String toString() { - return "MotionEvent{" + Integer.toHexString(System.identityHashCode(this)) - + " pointerId=" + getPointerId(0) - + " action=" + actionToString(getAction()) - + " x=" + getX() - + " y=" + getY() - + " pressure=" + getPressure() - + " size=" + getSize() - + " touchMajor=" + getTouchMajor() - + " touchMinor=" + getTouchMinor() - + " toolMajor=" + getToolMajor() - + " toolMinor=" + getToolMinor() - + " orientation=" + getOrientation() - + " meta=" + KeyEvent.metaStateToString(getMetaState()) - + " pointerCount=" + getPointerCount() - + " historySize=" + getHistorySize() - + " flags=0x" + Integer.toHexString(getFlags()) - + " edgeFlags=0x" + Integer.toHexString(getEdgeFlags()) - + " device=" + getDeviceId() - + " source=0x" + Integer.toHexString(getSource()) - + (getPointerCount() > 1 ? - " pointerId2=" + getPointerId(1) + " x2=" + getX(1) + " y2=" + getY(1) : "") - + "}"; + StringBuilder msg = new StringBuilder(); + msg.append("MotionEvent { action=").append(actionToString(getAction())); + + final int pointerCount = getPointerCount(); + for (int i = 0; i < pointerCount; i++) { + msg.append(", id[").append(i).append("]=").append(getPointerId(i)); + msg.append(", x[").append(i).append("]=").append(getX(i)); + msg.append(", y[").append(i).append("]=").append(getY(i)); + msg.append(", toolType[").append(i).append("]=").append( + toolTypeToString(getToolType(i))); + } + + msg.append(", buttonState=").append(KeyEvent.metaStateToString(getButtonState())); + msg.append(", metaState=").append(KeyEvent.metaStateToString(getMetaState())); + msg.append(", flags=0x").append(Integer.toHexString(getFlags())); + msg.append(", edgeFlags=0x").append(Integer.toHexString(getEdgeFlags())); + msg.append(", pointerCount=").append(pointerCount); + msg.append(", historySize=").append(getHistorySize()); + msg.append(", eventTime=").append(getEventTime()); + msg.append(", downTime=").append(getDownTime()); + msg.append(", deviceId=").append(getDeviceId()); + msg.append(", source=0x").append(Integer.toHexString(getSource())); + msg.append(" }"); + return msg.toString(); } /** @@ -2429,6 +2987,55 @@ public final class MotionEvent extends InputEvent implements Parcelable { } } + /** + * Returns a string that represents the symbolic name of the specified combined + * button state flags such as "0", "BUTTON_PRIMARY", + * "BUTTON_PRIMARY|BUTTON_SECONDARY" or an equivalent numeric constant such as "0x10000000" + * if unknown. + * + * @param buttonState The button state. + * @return The symbolic name of the specified combined button state flags. + * @hide + */ + public static String buttonStateToString(int buttonState) { + if (buttonState == 0) { + return "0"; + } + StringBuilder result = null; + int i = 0; + while (buttonState != 0) { + final boolean isSet = (buttonState & 1) != 0; + buttonState >>>= 1; // unsigned shift! + if (isSet) { + final String name = BUTTON_SYMBOLIC_NAMES[i]; + if (result == null) { + if (buttonState == 0) { + return name; + } + result = new StringBuilder(name); + } else { + result.append('|'); + result.append(name); + } + } + i += 1; + } + return result.toString(); + } + + /** + * Returns a string that represents the symbolic name of the specified tool type + * such as "TOOL_TYPE_FINGER" or an equivalent numeric constant such as "42" if unknown. + * + * @param toolType The tool type. + * @return The symbolic name of the specified tool type. + * @hide + */ + public static String toolTypeToString(int toolType) { + String symbolicName = TOOL_TYPE_SYMBOLIC_NAMES.get(toolType); + return symbolicName != null ? symbolicName : Integer.toString(toolType); + } + public static final Parcelable.Creator<MotionEvent> CREATOR = new Parcelable.Creator<MotionEvent>() { public MotionEvent createFromParcel(Parcel in) { @@ -2456,8 +3063,9 @@ public final class MotionEvent extends InputEvent implements Parcelable { /** * Transfer object for pointer coordinates. * - * Objects of this type can be used to manufacture new {@link MotionEvent} objects - * and to query pointer coordinate information in bulk. + * Objects of this type can be used to specify the pointer coordinates when + * creating new {@link MotionEvent} objects and to query pointer coordinates + * in bulk. * * Refer to {@link InputDevice} for information about how different kinds of * input devices and sources represent pointer coordinates. @@ -2483,6 +3091,15 @@ public final class MotionEvent extends InputEvent implements Parcelable { copyFrom(other); } + /** @hide */ + public static PointerCoords[] createArray(int size) { + PointerCoords[] array = new PointerCoords[size]; + for (int i = 0; i < size; i++) { + array[i] = new PointerCoords(); + } + return array; + } + /** * The X component of the pointer movement. * @@ -2743,4 +3360,71 @@ public final class MotionEvent extends InputEvent implements Parcelable { } } } + + /** + * Transfer object for pointer properties. + * + * Objects of this type can be used to specify the pointer id and tool type + * when creating new {@link MotionEvent} objects and to query pointer properties in bulk. + */ + public static final class PointerProperties { + /** + * Creates a pointer properties object with an invalid pointer id. + */ + public PointerProperties() { + clear(); + } + + /** + * Creates a pointer properties object as a copy of the contents of + * another pointer properties object. + * @param other + */ + public PointerProperties(PointerProperties other) { + copyFrom(other); + } + + /** @hide */ + public static PointerProperties[] createArray(int size) { + PointerProperties[] array = new PointerProperties[size]; + for (int i = 0; i < size; i++) { + array[i] = new PointerProperties(); + } + return array; + } + + /** + * The pointer id. + * Initially set to {@link #INVALID_POINTER_ID} (-1). + * + * @see MotionEvent#getPointerId(int) + */ + public int id; + + /** + * The pointer tool type. + * Initially set to 0. + * + * @see MotionEvent#getToolType(int) + */ + public int toolType; + + /** + * Resets the pointer properties to their initial values. + */ + public void clear() { + id = INVALID_POINTER_ID; + toolType = TOOL_TYPE_UNKNOWN; + } + + /** + * Copies the contents of another pointer properties object. + * + * @param other The pointer properties object to copy. + */ + public void copyFrom(PointerProperties other) { + id = other.id; + toolType = other.toolType; + } + } } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 791ffb9..4ee3a47 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -3173,6 +3173,23 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } /** + * Performs button-related actions during a touch down event. + * + * @param event The event. + * @return True if the down was consumed. + * + * @hide + */ + protected boolean performButtonActionOnTouchDown(MotionEvent event) { + if ((event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { + if (showContextMenu(event.getX(), event.getY(), event.getMetaState())) { + return true; + } + } + return false; + } + + /** * Bring up the context menu for this view. * * @return Whether a context menu was displayed. @@ -3182,6 +3199,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } /** + * Bring up the context menu for this view, referring to the item under the specified point. + * + * @param x The referenced x coordinate. + * @param y The referenced y coordinate. + * @param metaState The keyboard modifiers that were pressed. + * @return Whether a context menu was displayed. + * + * @hide + */ + public boolean showContextMenu(float x, float y, int metaState) { + return showContextMenu(); + } + + /** * Start an action mode. * * @param callback Callback that will control the lifecycle of the action mode @@ -5535,6 +5566,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility case MotionEvent.ACTION_DOWN: mHasPerformedLongPress = false; + if (performButtonActionOnTouchDown(event)) { + break; + } + // Walk up the hierarchy to determine if we're inside a scrolling container. boolean isInScrollingContainer = false; ViewParent p = getParent(); diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 35cca4f..f84b33b 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -129,11 +129,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // First touch target in the linked list of touch targets. private TouchTarget mFirstTouchTarget; - // Temporary arrays for splitting pointers. - private int[] mTmpPointerIndexMap; - private int[] mTmpPointerIds; - private MotionEvent.PointerCoords[] mTmpPointerCoords; - // For debugging only. You can see these in hierarchyviewer. @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) @ViewDebug.ExportedProperty(category = "events") @@ -1723,141 +1718,38 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } // Calculate the number of pointers to deliver. - final int oldPointerCount = event.getPointerCount(); - int newPointerCount = 0; - if (desiredPointerIdBits == TouchTarget.ALL_POINTER_IDS) { - newPointerCount = oldPointerCount; - } else { - for (int i = 0; i < oldPointerCount; i++) { - final int pointerId = event.getPointerId(i); - final int pointerIdBit = 1 << pointerId; - if ((pointerIdBit & desiredPointerIdBits) != 0) { - newPointerCount += 1; - } - } - } + final int oldPointerIdBits = event.getPointerIdBits(); + final int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits; // If for some reason we ended up in an inconsistent state where it looks like we // might produce a motion event with no pointers in it, then drop the event. - if (newPointerCount == 0) { + if (newPointerIdBits == 0) { return false; } // If the number of pointers is the same and we don't need to perform any fancy // irreversible transformations, then we can reuse the motion event for this // dispatch as long as we are careful to revert any changes we make. - final boolean reuse = newPointerCount == oldPointerCount - && (child == null || child.hasIdentityMatrix()); - if (reuse) { - if (child == null) { - handled = super.dispatchTouchEvent(event); - } else { - final float offsetX = mScrollX - child.mLeft; - final float offsetY = mScrollY - child.mTop; - event.offsetLocation(offsetX, offsetY); - - handled = child.dispatchTouchEvent(event); - - event.offsetLocation(-offsetX, -offsetY); - } - return handled; - } - - // Make a copy of the event. - // If the number of pointers is different, then we need to filter out irrelevant pointers - // as we make a copy of the motion event. - MotionEvent transformedEvent; - if (newPointerCount == oldPointerCount) { - transformedEvent = MotionEvent.obtain(event); - } else { - growTmpPointerArrays(newPointerCount); - final int[] newPointerIndexMap = mTmpPointerIndexMap; - final int[] newPointerIds = mTmpPointerIds; - final MotionEvent.PointerCoords[] newPointerCoords = mTmpPointerCoords; - - int newPointerIndex = 0; - int oldPointerIndex = 0; - while (newPointerIndex < newPointerCount) { - final int pointerId = event.getPointerId(oldPointerIndex); - final int pointerIdBits = 1 << pointerId; - if ((pointerIdBits & desiredPointerIdBits) != 0) { - newPointerIndexMap[newPointerIndex] = oldPointerIndex; - newPointerIds[newPointerIndex] = pointerId; - if (newPointerCoords[newPointerIndex] == null) { - newPointerCoords[newPointerIndex] = new MotionEvent.PointerCoords(); - } - - newPointerIndex += 1; - } - oldPointerIndex += 1; - } - - final int newAction; - if (cancel) { - newAction = MotionEvent.ACTION_CANCEL; - } else { - final int oldMaskedAction = oldAction & MotionEvent.ACTION_MASK; - if (oldMaskedAction == MotionEvent.ACTION_POINTER_DOWN - || oldMaskedAction == MotionEvent.ACTION_POINTER_UP) { - final int changedPointerId = event.getPointerId( - (oldAction & MotionEvent.ACTION_POINTER_INDEX_MASK) - >> MotionEvent.ACTION_POINTER_INDEX_SHIFT); - final int changedPointerIdBits = 1 << changedPointerId; - if ((changedPointerIdBits & desiredPointerIdBits) != 0) { - if (newPointerCount == 1) { - // The first/last pointer went down/up. - newAction = oldMaskedAction == MotionEvent.ACTION_POINTER_DOWN - ? MotionEvent.ACTION_DOWN : MotionEvent.ACTION_UP; - } else { - // A secondary pointer went down/up. - int newChangedPointerIndex = 0; - while (newPointerIds[newChangedPointerIndex] != changedPointerId) { - newChangedPointerIndex += 1; - } - newAction = oldMaskedAction | (newChangedPointerIndex - << MotionEvent.ACTION_POINTER_INDEX_SHIFT); - } - } else { - // An unrelated pointer changed. - newAction = MotionEvent.ACTION_MOVE; - } + // Otherwise we need to make a copy. + final MotionEvent transformedEvent; + if (newPointerIdBits == oldPointerIdBits) { + if (child == null || child.hasIdentityMatrix()) { + if (child == null) { + handled = super.dispatchTouchEvent(event); } else { - // Simple up/down/cancel/move motion action. - newAction = oldMaskedAction; - } - } + final float offsetX = mScrollX - child.mLeft; + final float offsetY = mScrollY - child.mTop; + event.offsetLocation(offsetX, offsetY); - transformedEvent = null; - final int historySize = event.getHistorySize(); - for (int historyIndex = 0; historyIndex <= historySize; historyIndex++) { - for (newPointerIndex = 0; newPointerIndex < newPointerCount; newPointerIndex++) { - final MotionEvent.PointerCoords c = newPointerCoords[newPointerIndex]; - oldPointerIndex = newPointerIndexMap[newPointerIndex]; - if (historyIndex != historySize) { - event.getHistoricalPointerCoords(oldPointerIndex, historyIndex, c); - } else { - event.getPointerCoords(oldPointerIndex, c); - } - } + handled = child.dispatchTouchEvent(event); - final long eventTime; - if (historyIndex != historySize) { - eventTime = event.getHistoricalEventTime(historyIndex); - } else { - eventTime = event.getEventTime(); - } - - if (transformedEvent == null) { - transformedEvent = MotionEvent.obtain( - event.getDownTime(), eventTime, newAction, - newPointerCount, newPointerIds, newPointerCoords, - event.getMetaState(), event.getXPrecision(), event.getYPrecision(), - event.getDeviceId(), event.getEdgeFlags(), event.getSource(), - event.getFlags()); - } else { - transformedEvent.addBatch(eventTime, newPointerCoords, 0); + event.offsetLocation(-offsetX, -offsetY); } + return handled; } + transformedEvent = MotionEvent.obtain(event); + } else { + transformedEvent = event.split(newPointerIdBits); } // Perform any necessary transformations and dispatch. @@ -1880,36 +1772,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } /** - * Enlarge the temporary pointer arrays for splitting pointers. - * May discard contents (but keeps PointerCoords objects to avoid reallocating them). - */ - private void growTmpPointerArrays(int desiredCapacity) { - final MotionEvent.PointerCoords[] oldTmpPointerCoords = mTmpPointerCoords; - int capacity; - if (oldTmpPointerCoords != null) { - capacity = oldTmpPointerCoords.length; - if (desiredCapacity <= capacity) { - return; - } - } else { - capacity = 4; - } - - while (capacity < desiredCapacity) { - capacity *= 2; - } - - mTmpPointerIndexMap = new int[capacity]; - mTmpPointerIds = new int[capacity]; - mTmpPointerCoords = new MotionEvent.PointerCoords[capacity]; - - if (oldTmpPointerCoords != null) { - System.arraycopy(oldTmpPointerCoords, 0, mTmpPointerCoords, 0, - oldTmpPointerCoords.length); - } - } - - /** * Enable or disable the splitting of MotionEvents to multiple children during touch event * dispatch. This behavior is enabled by default for applications that target an * SDK version of {@link Build.VERSION_CODES#HONEYCOMB} or newer. diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index df4c4ed..f4300a5 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -2533,6 +2533,21 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te return mContextMenuInfo; } + /** @hide */ + @Override + public boolean showContextMenu(float x, float y, int metaState) { + final int position = pointToPosition((int)x, (int)y); + if (position != INVALID_POSITION) { + final long id = mAdapter.getItemId(position); + View child = getChildAt(position - mFirstPosition); + if (child != null) { + mContextMenuInfo = createContextMenuInfo(child, position, id); + return super.showContextMenuForChild(AbsListView.this); + } + } + return super.showContextMenu(x, y, metaState); + } + @Override public boolean showContextMenuForChild(View originalView) { final int longPressPosition = getPositionForView(originalView); @@ -2846,6 +2861,12 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te break; } } + + if (performButtonActionOnTouchDown(ev)) { + if (mTouchMode == TOUCH_MODE_DOWN) { + removeCallbacks(mPendingCheckForTap); + } + } break; } diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java index c34cb9e..d789584 100644 --- a/core/java/com/android/internal/widget/PointerLocationView.java +++ b/core/java/com/android/internal/widget/PointerLocationView.java @@ -320,7 +320,8 @@ public class PointerLocationView extends View { } } - private void logPointerCoords(int action, int index, MotionEvent.PointerCoords coords, int id) { + private void logPointerCoords(int action, int index, MotionEvent.PointerCoords coords, int id, + int toolType, int buttonState) { final String prefix; switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: @@ -386,26 +387,16 @@ public class PointerLocationView extends View { .append("deg") .append(" VScroll=").append(coords.getAxisValue(MotionEvent.AXIS_VSCROLL), 1) .append(" HScroll=").append(coords.getAxisValue(MotionEvent.AXIS_HSCROLL), 1) + .append(" ToolType=").append(MotionEvent.toolTypeToString(toolType)) + .append(" ButtonState=").append(MotionEvent.buttonStateToString(buttonState)) .toString()); } public void addPointerEvent(MotionEvent event) { synchronized (mPointers) { - int action = event.getAction(); - - //Log.i(TAG, "Motion: action=0x" + Integer.toHexString(action) - // + " pointers=" + event.getPointerCount()); - + final int action = event.getAction(); int NP = mPointers.size(); - - //mRect.set(0, 0, getWidth(), mHeaderBottom+1); - //invalidate(mRect); - //if (mCurDown) { - // mRect.set(mCurX-mCurWidth-3, mCurY-mCurWidth-3, - // mCurX+mCurWidth+3, mCurY+mCurWidth+3); - //} else { - // mRect.setEmpty(); - //} + if (action == MotionEvent.ACTION_DOWN || (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_DOWN) { final int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) @@ -456,7 +447,8 @@ public class PointerLocationView extends View { final PointerCoords coords = ps != null ? ps.mCoords : mHoverCoords; event.getHistoricalPointerCoords(i, historyPos, coords); if (mPrintCoords) { - logPointerCoords(action, i, coords, id); + logPointerCoords(action, i, coords, id, + event.getToolType(i), event.getButtonState()); } if (ps != null) { ps.addTrace(coords.x, coords.y); @@ -469,7 +461,8 @@ public class PointerLocationView extends View { final PointerCoords coords = ps != null ? ps.mCoords : mHoverCoords; event.getPointerCoords(i, coords); if (mPrintCoords) { - logPointerCoords(action, i, coords, id); + logPointerCoords(action, i, coords, id, + event.getToolType(i), event.getButtonState()); } if (ps != null) { ps.addTrace(coords.x, coords.y); @@ -500,12 +493,7 @@ public class PointerLocationView extends View { ps.addTrace(Float.NaN, Float.NaN); } } - - //if (mCurDown) { - // mRect.union(mCurX-mCurWidth-3, mCurY-mCurWidth-3, - // mCurX+mCurWidth+3, mCurY+mCurWidth+3); - //} - //invalidate(mRect); + postInvalidate(); } } diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp index 2ede7ec..fef06b2 100644 --- a/core/jni/android_view_MotionEvent.cpp +++ b/core/jni/android_view_MotionEvent.cpp @@ -55,6 +55,11 @@ static struct { jfieldID orientation; } gPointerCoordsClassInfo; +static struct { + jfieldID id; + jfieldID toolType; +} gPointerPropertiesClassInfo; + // ---------------------------------------------------------------------------- MotionEvent* android_view_MotionEvent_getNativePtr(JNIEnv* env, jobject eventObj) { @@ -115,17 +120,17 @@ static bool validatePointerCount(JNIEnv* env, jint pointerCount) { return true; } -static bool validatePointerIdsArray(JNIEnv* env, jintArray pointerIdsArray, +static bool validatePointerPropertiesArray(JNIEnv* env, jobjectArray pointerPropertiesObjArray, size_t pointerCount) { - if (!pointerIdsArray) { + if (!pointerPropertiesObjArray) { jniThrowException(env, "java/lang/IllegalArgumentException", - "pointerIds array must not be null"); + "pointerProperties array must not be null"); return false; } - size_t length = size_t(env->GetArrayLength(pointerIdsArray)); + size_t length = size_t(env->GetArrayLength(pointerPropertiesObjArray)); if (length < pointerCount) { jniThrowException(env, "java/lang/IllegalArgumentException", - "pointerIds array must be large enough to hold all pointers"); + "pointerProperties array must be large enough to hold all pointers"); return false; } return true; @@ -174,6 +179,15 @@ static bool validatePointerCoords(JNIEnv* env, jobject pointerCoordsObj) { return true; } +static bool validatePointerProperties(JNIEnv* env, jobject pointerPropertiesObj) { + if (!pointerPropertiesObj) { + jniThrowException(env, "java/lang/IllegalArgumentException", + "pointerProperties must not be null"); + return false; + } + return true; +} + static void pointerCoordsToNative(JNIEnv* env, jobject pointerCoordsObj, float xOffset, float yOffset, PointerCoords* outRawPointerCoords) { outRawPointerCoords->clear(); @@ -300,17 +314,36 @@ static void pointerCoordsFromNative(JNIEnv* env, const PointerCoords* rawPointer env->SetLongField(outPointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisBits, outBits); } +static void pointerPropertiesToNative(JNIEnv* env, jobject pointerPropertiesObj, + PointerProperties* outPointerProperties) { + outPointerProperties->clear(); + outPointerProperties->id = env->GetIntField(pointerPropertiesObj, + gPointerPropertiesClassInfo.id); + outPointerProperties->toolType = env->GetIntField(pointerPropertiesObj, + gPointerPropertiesClassInfo.toolType); +} + +static void pointerPropertiesFromNative(JNIEnv* env, const PointerProperties* pointerProperties, + jobject outPointerPropertiesObj) { + env->SetIntField(outPointerPropertiesObj, gPointerPropertiesClassInfo.id, + pointerProperties->id); + env->SetIntField(outPointerPropertiesObj, gPointerPropertiesClassInfo.toolType, + pointerProperties->toolType); +} + // ---------------------------------------------------------------------------- static jint android_view_MotionEvent_nativeInitialize(JNIEnv* env, jclass clazz, jint nativePtr, - jint deviceId, jint source, jint action, jint flags, jint edgeFlags, jint metaState, + jint deviceId, jint source, jint action, jint flags, jint edgeFlags, + jint metaState, jint buttonState, jfloat xOffset, jfloat yOffset, jfloat xPrecision, jfloat yPrecision, jlong downTimeNanos, jlong eventTimeNanos, - jint pointerCount, jintArray pointerIdsArray, jobjectArray pointerCoordsObjArray) { + jint pointerCount, jobjectArray pointerPropertiesObjArray, + jobjectArray pointerCoordsObjArray) { if (!validatePointerCount(env, pointerCount) - || !validatePointerIdsArray(env, pointerIdsArray, pointerCount) + || !validatePointerPropertiesArray(env, pointerPropertiesObjArray, pointerCount) || !validatePointerCoordsObjArray(env, pointerCoordsObjArray, pointerCount)) { return 0; } @@ -320,29 +353,37 @@ static jint android_view_MotionEvent_nativeInitialize(JNIEnv* env, jclass clazz, event = new MotionEvent(); } + PointerProperties pointerProperties[pointerCount]; PointerCoords rawPointerCoords[pointerCount]; for (jint i = 0; i < pointerCount; i++) { + jobject pointerPropertiesObj = env->GetObjectArrayElement(pointerPropertiesObjArray, i); + if (!pointerPropertiesObj) { + goto Error; + } + pointerPropertiesToNative(env, pointerPropertiesObj, &pointerProperties[i]); + env->DeleteLocalRef(pointerPropertiesObj); + jobject pointerCoordsObj = env->GetObjectArrayElement(pointerCoordsObjArray, i); if (!pointerCoordsObj) { jniThrowNullPointerException(env, "pointerCoords"); - if (!nativePtr) { - delete event; - } - return 0; + goto Error; } pointerCoordsToNative(env, pointerCoordsObj, xOffset, yOffset, &rawPointerCoords[i]); env->DeleteLocalRef(pointerCoordsObj); } - int* pointerIds = static_cast<int*>(env->GetPrimitiveArrayCritical(pointerIdsArray, NULL)); - - event->initialize(deviceId, source, action, flags, edgeFlags, metaState, + event->initialize(deviceId, source, action, flags, edgeFlags, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision, - downTimeNanos, eventTimeNanos, pointerCount, pointerIds, rawPointerCoords); + downTimeNanos, eventTimeNanos, pointerCount, pointerProperties, rawPointerCoords); - env->ReleasePrimitiveArrayCritical(pointerIdsArray, pointerIds, JNI_ABORT); return reinterpret_cast<jint>(event); + +Error: + if (!nativePtr) { + delete event; + } + return 0; } static jint android_view_MotionEvent_nativeCopy(JNIEnv* env, jclass clazz, @@ -454,12 +495,30 @@ static jint android_view_MotionEvent_nativeGetMetaState(JNIEnv* env, jclass claz return event->getMetaState(); } +static jint android_view_MotionEvent_nativeGetButtonState(JNIEnv* env, jclass clazz, + jint nativePtr) { + MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); + return event->getButtonState(); +} + static void android_view_MotionEvent_nativeOffsetLocation(JNIEnv* env, jclass clazz, jint nativePtr, jfloat deltaX, jfloat deltaY) { MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); return event->offsetLocation(deltaX, deltaY); } +static jfloat android_view_MotionEvent_nativeGetXOffset(JNIEnv* env, jclass clazz, + jint nativePtr) { + MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); + return event->getXOffset(); +} + +static jfloat android_view_MotionEvent_nativeGetYOffset(JNIEnv* env, jclass clazz, + jint nativePtr) { + MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); + return event->getYOffset(); +} + static jfloat android_view_MotionEvent_nativeGetXPrecision(JNIEnv* env, jclass clazz, jint nativePtr) { MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); @@ -478,6 +537,12 @@ static jlong android_view_MotionEvent_nativeGetDownTimeNanos(JNIEnv* env, jclass return event->getDownTime(); } +static void android_view_MotionEvent_nativeSetDownTimeNanos(JNIEnv* env, jclass clazz, + jint nativePtr, jlong downTimeNanos) { + MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); + event->setDownTime(downTimeNanos); +} + static jint android_view_MotionEvent_nativeGetPointerCount(JNIEnv* env, jclass clazz, jint nativePtr) { MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); @@ -494,6 +559,16 @@ static jint android_view_MotionEvent_nativeGetPointerId(JNIEnv* env, jclass claz return event->getPointerId(pointerIndex); } +static jint android_view_MotionEvent_nativeGetToolType(JNIEnv* env, jclass clazz, + jint nativePtr, jint pointerIndex) { + MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); + size_t pointerCount = event->getPointerCount(); + if (!validatePointerIndex(env, pointerIndex, pointerCount)) { + return -1; + } + return event->getToolType(pointerIndex); +} + static jint android_view_MotionEvent_nativeFindPointerIndex(JNIEnv* env, jclass clazz, jint nativePtr, jint pointerId) { MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); @@ -581,6 +656,19 @@ static void android_view_MotionEvent_nativeGetPointerCoords(JNIEnv* env, jclass outPointerCoordsObj); } +static void android_view_MotionEvent_nativeGetPointerProperties(JNIEnv* env, jclass clazz, + jint nativePtr, jint pointerIndex, jobject outPointerPropertiesObj) { + MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); + size_t pointerCount = event->getPointerCount(); + if (!validatePointerIndex(env, pointerIndex, pointerCount) + || !validatePointerProperties(env, outPointerPropertiesObj)) { + return; + } + + const PointerProperties* pointerProperties = event->getPointerProperties(pointerIndex); + pointerPropertiesFromNative(env, pointerProperties, outPointerPropertiesObj); +} + static void android_view_MotionEvent_nativeScale(JNIEnv* env, jclass clazz, jint nativePtr, jfloat scale) { MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); @@ -630,7 +718,8 @@ static void android_view_MotionEvent_nativeWriteToParcel(JNIEnv* env, jclass cla static JNINativeMethod gMotionEventMethods[] = { /* name, signature, funcPtr */ { "nativeInitialize", - "(IIIIIIIFFFFJJI[I[Landroid/view/MotionEvent$PointerCoords;)I", + "(IIIIIIIIFFFFJJI[Landroid/view/MotionEvent$PointerProperties;" + "[Landroid/view/MotionEvent$PointerCoords;)I", (void*)android_view_MotionEvent_nativeInitialize }, { "nativeCopy", "(IIZ)I", @@ -674,9 +763,18 @@ static JNINativeMethod gMotionEventMethods[] = { { "nativeGetMetaState", "(I)I", (void*)android_view_MotionEvent_nativeGetMetaState }, + { "nativeGetButtonState", + "(I)I", + (void*)android_view_MotionEvent_nativeGetButtonState }, { "nativeOffsetLocation", "(IFF)V", (void*)android_view_MotionEvent_nativeOffsetLocation }, + { "nativeGetXOffset", + "(I)F", + (void*)android_view_MotionEvent_nativeGetXOffset }, + { "nativeGetYOffset", + "(I)F", + (void*)android_view_MotionEvent_nativeGetYOffset }, { "nativeGetXPrecision", "(I)F", (void*)android_view_MotionEvent_nativeGetXPrecision }, @@ -686,12 +784,18 @@ static JNINativeMethod gMotionEventMethods[] = { { "nativeGetDownTimeNanos", "(I)J", (void*)android_view_MotionEvent_nativeGetDownTimeNanos }, + { "nativeSetDownTimeNanos", + "(IJ)V", + (void*)android_view_MotionEvent_nativeSetDownTimeNanos }, { "nativeGetPointerCount", "(I)I", (void*)android_view_MotionEvent_nativeGetPointerCount }, { "nativeGetPointerId", "(II)I", (void*)android_view_MotionEvent_nativeGetPointerId }, + { "nativeGetToolType", + "(II)I", + (void*)android_view_MotionEvent_nativeGetToolType }, { "nativeFindPointerIndex", "(II)I", (void*)android_view_MotionEvent_nativeFindPointerIndex }, @@ -710,6 +814,9 @@ static JNINativeMethod gMotionEventMethods[] = { { "nativeGetPointerCoords", "(IIILandroid/view/MotionEvent$PointerCoords;)V", (void*)android_view_MotionEvent_nativeGetPointerCoords }, + { "nativeGetPointerProperties", + "(IILandroid/view/MotionEvent$PointerProperties;)V", + (void*)android_view_MotionEvent_nativeGetPointerProperties }, { "nativeScale", "(IF)V", (void*)android_view_MotionEvent_nativeScale }, @@ -781,6 +888,13 @@ int register_android_view_MotionEvent(JNIEnv* env) { GET_FIELD_ID(gPointerCoordsClassInfo.orientation, clazz, "orientation", "F"); + FIND_CLASS(clazz, "android/view/MotionEvent$PointerProperties"); + + GET_FIELD_ID(gPointerPropertiesClassInfo.id, clazz, + "id", "I"); + GET_FIELD_ID(gPointerPropertiesClassInfo.toolType, clazz, + "toolType", "I"); + return 0; } diff --git a/include/ui/Input.h b/include/ui/Input.h index c7ebf56..ba1c6b4 100644 --- a/include/ui/Input.h +++ b/include/ui/Input.h @@ -157,14 +157,6 @@ enum { }; /* - * Button state. - */ -enum { - // Primary button pressed (left mouse button). - BUTTON_STATE_PRIMARY = 1 << 0, -}; - -/* * Describes the basic configuration of input devices that are present. */ struct InputConfiguration { @@ -235,6 +227,29 @@ private: }; /* + * Pointer property data. + */ +struct PointerProperties { + // The id of the pointer. + int32_t id; + + // The pointer tool type. + int32_t toolType; + + inline void clear() { + id = -1; + toolType = 0; + } + + bool operator==(const PointerProperties& other) const; + inline bool operator!=(const PointerProperties& other) const { + return !(*this == other); + } + + void copyFrom(const PointerProperties& other); +}; + +/* * Input events. */ class InputEvent : public AInputEvent { @@ -346,6 +361,8 @@ public: inline void setMetaState(int32_t metaState) { mMetaState = metaState; } + inline int32_t getButtonState() const { return mButtonState; } + inline float getXOffset() const { return mXOffset; } inline float getYOffset() const { return mYOffset; } @@ -356,9 +373,21 @@ public: inline nsecs_t getDownTime() const { return mDownTime; } - inline size_t getPointerCount() const { return mPointerIds.size(); } + inline void setDownTime(nsecs_t downTime) { mDownTime = downTime; } + + inline size_t getPointerCount() const { return mPointerProperties.size(); } - inline int32_t getPointerId(size_t pointerIndex) const { return mPointerIds[pointerIndex]; } + inline const PointerProperties* getPointerProperties(size_t pointerIndex) const { + return &mPointerProperties[pointerIndex]; + } + + inline int32_t getPointerId(size_t pointerIndex) const { + return mPointerProperties[pointerIndex].id; + } + + inline int32_t getToolType(size_t pointerIndex) const { + return mPointerProperties[pointerIndex].toolType; + } inline nsecs_t getEventTime() const { return mSampleEventTimes[getHistorySize()]; } @@ -490,6 +519,7 @@ public: int32_t flags, int32_t edgeFlags, int32_t metaState, + int32_t buttonState, float xOffset, float yOffset, float xPrecision, @@ -497,7 +527,7 @@ public: nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, - const int32_t* pointerIds, + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); void copyFrom(const MotionEvent* other, bool keepHistory); @@ -523,7 +553,9 @@ public: } // Low-level accessors. - inline const int32_t* getPointerIds() const { return mPointerIds.array(); } + inline const PointerProperties* getPointerProperties() const { + return mPointerProperties.array(); + } inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.array(); } inline const PointerCoords* getSamplePointerCoords() const { return mSamplePointerCoords.array(); @@ -534,12 +566,13 @@ protected: int32_t mFlags; int32_t mEdgeFlags; int32_t mMetaState; + int32_t mButtonState; float mXOffset; float mYOffset; float mXPrecision; float mYPrecision; nsecs_t mDownTime; - Vector<int32_t> mPointerIds; + Vector<PointerProperties> mPointerProperties; Vector<nsecs_t> mSampleEventTimes; Vector<PointerCoords> mSamplePointerCoords; }; diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h index 119db81..95e4447 100644 --- a/include/ui/InputTransport.h +++ b/include/ui/InputTransport.h @@ -136,6 +136,7 @@ struct InputMessage { int32_t action; int32_t flags; int32_t metaState; + int32_t buttonState; int32_t edgeFlags; nsecs_t downTime; float xOffset; @@ -143,7 +144,7 @@ struct InputMessage { float xPrecision; float yPrecision; size_t pointerCount; - int32_t pointerIds[MAX_POINTERS]; + PointerProperties pointerProperties[MAX_POINTERS]; size_t sampleCount; SampleData sampleData[0]; // variable length } motion; @@ -221,6 +222,7 @@ public: int32_t flags, int32_t edgeFlags, int32_t metaState, + int32_t buttonState, float xOffset, float yOffset, float xPrecision, @@ -228,7 +230,7 @@ public: nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, - const int32_t* pointerIds, + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); /* Appends a motion sample to a motion event unless already consumed. diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp index d811dd7..1ba38a7 100644 --- a/libs/ui/Input.cpp +++ b/libs/ui/Input.cpp @@ -373,6 +373,19 @@ void PointerCoords::copyFrom(const PointerCoords& other) { } +// --- PointerProperties --- + +bool PointerProperties::operator==(const PointerProperties& other) const { + return id == other.id + && toolType == other.toolType; +} + +void PointerProperties::copyFrom(const PointerProperties& other) { + id = other.id; + toolType = other.toolType; +} + + // --- MotionEvent --- void MotionEvent::initialize( @@ -382,6 +395,7 @@ void MotionEvent::initialize( int32_t flags, int32_t edgeFlags, int32_t metaState, + int32_t buttonState, float xOffset, float yOffset, float xPrecision, @@ -389,20 +403,21 @@ void MotionEvent::initialize( nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, - const int32_t* pointerIds, + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { InputEvent::initialize(deviceId, source); mAction = action; mFlags = flags; mEdgeFlags = edgeFlags; mMetaState = metaState; + mButtonState = buttonState; mXOffset = xOffset; mYOffset = yOffset; mXPrecision = xPrecision; mYPrecision = yPrecision; mDownTime = downTime; - mPointerIds.clear(); - mPointerIds.appendArray(pointerIds, pointerCount); + mPointerProperties.clear(); + mPointerProperties.appendArray(pointerProperties, pointerCount); mSampleEventTimes.clear(); mSamplePointerCoords.clear(); addSample(eventTime, pointerCoords); @@ -414,12 +429,13 @@ void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { mFlags = other->mFlags; mEdgeFlags = other->mEdgeFlags; mMetaState = other->mMetaState; + mButtonState = other->mButtonState; mXOffset = other->mXOffset; mYOffset = other->mYOffset; mXPrecision = other->mXPrecision; mYPrecision = other->mYPrecision; mDownTime = other->mDownTime; - mPointerIds = other->mPointerIds; + mPointerProperties = other->mPointerProperties; if (keepHistory) { mSampleEventTimes = other->mSampleEventTimes; @@ -484,9 +500,9 @@ float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, } ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const { - size_t pointerCount = mPointerIds.size(); + size_t pointerCount = mPointerProperties.size(); for (size_t i = 0; i < pointerCount; i++) { - if (mPointerIds.itemAt(i) == pointerId) { + if (mPointerProperties.itemAt(i).id == pointerId) { return i; } } @@ -583,21 +599,25 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { mFlags = parcel->readInt32(); mEdgeFlags = parcel->readInt32(); mMetaState = parcel->readInt32(); + mButtonState = parcel->readInt32(); mXOffset = parcel->readFloat(); mYOffset = parcel->readFloat(); mXPrecision = parcel->readFloat(); mYPrecision = parcel->readFloat(); mDownTime = parcel->readInt64(); - mPointerIds.clear(); - mPointerIds.setCapacity(pointerCount); + mPointerProperties.clear(); + mPointerProperties.setCapacity(pointerCount); mSampleEventTimes.clear(); mSampleEventTimes.setCapacity(sampleCount); mSamplePointerCoords.clear(); mSamplePointerCoords.setCapacity(sampleCount * pointerCount); for (size_t i = 0; i < pointerCount; i++) { - mPointerIds.push(parcel->readInt32()); + mPointerProperties.push(); + PointerProperties& properties = mPointerProperties.editTop(); + properties.id = parcel->readInt32(); + properties.toolType = parcel->readInt32(); } while (sampleCount-- > 0) { @@ -614,7 +634,7 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { } status_t MotionEvent::writeToParcel(Parcel* parcel) const { - size_t pointerCount = mPointerIds.size(); + size_t pointerCount = mPointerProperties.size(); size_t sampleCount = mSampleEventTimes.size(); parcel->writeInt32(pointerCount); @@ -626,6 +646,7 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { parcel->writeInt32(mFlags); parcel->writeInt32(mEdgeFlags); parcel->writeInt32(mMetaState); + parcel->writeInt32(mButtonState); parcel->writeFloat(mXOffset); parcel->writeFloat(mYOffset); parcel->writeFloat(mXPrecision); @@ -633,7 +654,9 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { parcel->writeInt64(mDownTime); for (size_t i = 0; i < pointerCount; i++) { - parcel->writeInt32(mPointerIds.itemAt(i)); + const PointerProperties& properties = mPointerProperties.itemAt(i); + parcel->writeInt32(properties.id); + parcel->writeInt32(properties.toolType); } const PointerCoords* pc = mSamplePointerCoords.array(); diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp index 93d0d1f..ffdfe66 100644 --- a/libs/ui/InputTransport.cpp +++ b/libs/ui/InputTransport.cpp @@ -366,6 +366,7 @@ status_t InputPublisher::publishMotionEvent( int32_t flags, int32_t edgeFlags, int32_t metaState, + int32_t buttonState, float xOffset, float yOffset, float xPrecision, @@ -373,16 +374,17 @@ status_t InputPublisher::publishMotionEvent( nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, - const int32_t* pointerIds, + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { #if DEBUG_TRANSPORT_ACTIONS LOGD("channel '%s' publisher ~ publishMotionEvent: deviceId=%d, source=0x%x, " - "action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, xOffset=%f, yOffset=%f, " + "action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, buttonState=0x%x, " + "xOffset=%f, yOffset=%f, " "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, " "pointerCount=%d", mChannel->getName().string(), - deviceId, source, action, flags, edgeFlags, metaState, xOffset, yOffset, - xPrecision, yPrecision, downTime, eventTime, pointerCount); + deviceId, source, action, flags, edgeFlags, metaState, buttonState, + xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount); #endif if (pointerCount > MAX_POINTERS || pointerCount < 1) { @@ -400,6 +402,7 @@ status_t InputPublisher::publishMotionEvent( mSharedMessage->motion.flags = flags; mSharedMessage->motion.edgeFlags = edgeFlags; mSharedMessage->motion.metaState = metaState; + mSharedMessage->motion.buttonState = buttonState; mSharedMessage->motion.xOffset = xOffset; mSharedMessage->motion.yOffset = yOffset; mSharedMessage->motion.xPrecision = xPrecision; @@ -411,7 +414,7 @@ status_t InputPublisher::publishMotionEvent( mSharedMessage->motion.sampleData[0].eventTime = eventTime; for (size_t i = 0; i < pointerCount; i++) { - mSharedMessage->motion.pointerIds[i] = pointerIds[i]; + mSharedMessage->motion.pointerProperties[i].copyFrom(pointerProperties[i]); mSharedMessage->motion.sampleData[0].coords[i].copyFrom(pointerCoords[i]); } @@ -694,6 +697,7 @@ void InputConsumer::populateMotionEvent(MotionEvent* motionEvent) const { mSharedMessage->motion.flags, mSharedMessage->motion.edgeFlags, mSharedMessage->motion.metaState, + mSharedMessage->motion.buttonState, mSharedMessage->motion.xOffset, mSharedMessage->motion.yOffset, mSharedMessage->motion.xPrecision, @@ -701,7 +705,7 @@ void InputConsumer::populateMotionEvent(MotionEvent* motionEvent) const { mSharedMessage->motion.downTime, mSharedMessage->motion.sampleData[0].eventTime, mSharedMessage->motion.pointerCount, - mSharedMessage->motion.pointerIds, + mSharedMessage->motion.pointerProperties, mSharedMessage->motion.sampleData[0].coords); size_t sampleCount = mSharedMessage->motion.sampleCount; diff --git a/libs/ui/tests/InputEvent_test.cpp b/libs/ui/tests/InputEvent_test.cpp index b77489e..e48d5b7 100644 --- a/libs/ui/tests/InputEvent_test.cpp +++ b/libs/ui/tests/InputEvent_test.cpp @@ -232,7 +232,14 @@ const float MotionEventTest::X_OFFSET = 1.0f; const float MotionEventTest::Y_OFFSET = 1.1f; void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { - int32_t pointerIds[] = { 1, 2 }; + PointerProperties pointerProperties[2]; + pointerProperties[0].clear(); + pointerProperties[0].id = 1; + pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + pointerProperties[1].clear(); + pointerProperties[1].id = 2; + pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + PointerCoords pointerCoords[2]; pointerCoords[0].clear(); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 10); @@ -256,10 +263,10 @@ void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28); event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE, AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, - AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, + AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY, X_OFFSET, Y_OFFSET, 2.0f, 2.1f, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, - 2, pointerIds, pointerCoords); + 2, pointerProperties, pointerCoords); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111); @@ -311,6 +318,7 @@ void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) { ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, event->getFlags()); ASSERT_EQ(AMOTION_EVENT_EDGE_FLAG_TOP, event->getEdgeFlags()); ASSERT_EQ(AMETA_ALT_ON, event->getMetaState()); + ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, event->getButtonState()); ASSERT_EQ(X_OFFSET, event->getXOffset()); ASSERT_EQ(Y_OFFSET, event->getYOffset()); ASSERT_EQ(2.0f, event->getXPrecision()); @@ -319,7 +327,9 @@ void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) { ASSERT_EQ(2U, event->getPointerCount()); ASSERT_EQ(1, event->getPointerId(0)); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, event->getToolType(0)); ASSERT_EQ(2, event->getPointerId(1)); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, event->getToolType(1)); ASSERT_EQ(2U, event->getHistorySize()); @@ -534,19 +544,20 @@ TEST_F(MotionEventTest, Transform) { const float ROTATION = ARC * 2; const size_t pointerCount = 11; - int pointerIds[pointerCount]; + PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; for (size_t i = 0; i < pointerCount; i++) { float angle = float(i * ARC * PI_180); - pointerIds[i] = i; + pointerProperties[i].clear(); + pointerProperties[i].id = i; pointerCoords[i].clear(); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, sinf(angle) * RADIUS + 3); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, -cosf(angle) * RADIUS + 2); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle); } MotionEvent event; - event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, - 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords); + event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); float originalRawX = 0 + 3; float originalRawY = -RADIUS + 2; diff --git a/libs/ui/tests/InputPublisherAndConsumer_test.cpp b/libs/ui/tests/InputPublisherAndConsumer_test.cpp index 6e18a4f..fcc4cad 100644 --- a/libs/ui/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/ui/tests/InputPublisherAndConsumer_test.cpp @@ -156,13 +156,19 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent( const int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; const int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP; const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON; + const int32_t buttonState = AMOTION_EVENT_BUTTON_PRIMARY; const float xOffset = -10; const float yOffset = -20; const float xPrecision = 0.25; const float yPrecision = 0.5; const nsecs_t downTime = 3; const size_t pointerCount = 3; - const int32_t pointerIds[pointerCount] = { 2, 0, 1 }; + PointerProperties pointerProperties[pointerCount]; + for (size_t i = 0; i < pointerCount; i++) { + pointerProperties[i].clear(); + pointerProperties[i].id = (i + 2) % pointerCount; + pointerProperties[i].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + } Vector<nsecs_t> sampleEventTimes; Vector<PointerCoords> samplePointerCoords; @@ -186,8 +192,9 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent( } status = mPublisher->publishMotionEvent(deviceId, source, action, flags, edgeFlags, - metaState, xOffset, yOffset, xPrecision, yPrecision, - downTime, sampleEventTimes[0], pointerCount, pointerIds, samplePointerCoords.array()); + metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision, + downTime, sampleEventTimes[0], pointerCount, + pointerProperties, samplePointerCoords.array()); ASSERT_EQ(OK, status) << "publisher publishMotionEvent should return OK"; @@ -234,6 +241,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent( EXPECT_EQ(flags, motionEvent->getFlags()); EXPECT_EQ(edgeFlags, motionEvent->getEdgeFlags()); EXPECT_EQ(metaState, motionEvent->getMetaState()); + EXPECT_EQ(buttonState, motionEvent->getButtonState()); EXPECT_EQ(xPrecision, motionEvent->getXPrecision()); EXPECT_EQ(yPrecision, motionEvent->getYPrecision()); EXPECT_EQ(downTime, motionEvent->getDownTime()); @@ -243,7 +251,8 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent( for (size_t i = 0; i < pointerCount; i++) { SCOPED_TRACE(i); - EXPECT_EQ(pointerIds[i], motionEvent->getPointerId(i)); + EXPECT_EQ(pointerProperties[i].id, motionEvent->getPointerId(i)); + EXPECT_EQ(pointerProperties[i].toolType, motionEvent->getToolType(i)); } for (size_t sampleIndex = 0; sampleIndex < lastSampleIndex; sampleIndex++) { @@ -352,17 +361,20 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenNotReset_ReturnsErr ASSERT_NO_FATAL_FAILURE(Initialize()); const size_t pointerCount = 1; - int32_t pointerIds[pointerCount] = { 0 }; + PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; - pointerCoords[0].clear(); + for (size_t i = 0; i < pointerCount; i++) { + pointerProperties[i].clear(); + pointerCoords[i].clear(); + } - status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - pointerCount, pointerIds, pointerCoords); + status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(OK, status) << "publisher publishMotionEvent should return OK"; - status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - pointerCount, pointerIds, pointerCoords); + status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(INVALID_OPERATION, status) << "publisher publishMotionEvent should return INVALID_OPERATION because "; "the publisher was not reset"; @@ -373,11 +385,11 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessTha ASSERT_NO_FATAL_FAILURE(Initialize()); const size_t pointerCount = 0; - int32_t pointerIds[pointerCount]; + PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; - status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - pointerCount, pointerIds, pointerCoords); + status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } @@ -387,11 +399,15 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreater ASSERT_NO_FATAL_FAILURE(Initialize()); const size_t pointerCount = MAX_POINTERS + 1; - int32_t pointerIds[pointerCount]; + PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; + for (size_t i = 0; i < pointerCount; i++) { + pointerProperties[i].clear(); + pointerCoords[i].clear(); + } - status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - pointerCount, pointerIds, pointerCoords); + status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } @@ -432,11 +448,15 @@ TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenPublishedMotionEven ASSERT_NO_FATAL_FAILURE(Initialize()); const size_t pointerCount = MAX_POINTERS; - int32_t pointerIds[pointerCount]; + PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; + for (size_t i = 0; i < pointerCount; i++) { + pointerProperties[i].clear(); + pointerCoords[i].clear(); + } status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_DOWN, - 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords); + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(OK, status); status = mPublisher->appendMotionSample(0, pointerCoords); @@ -449,11 +469,15 @@ TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenAlreadyConsumed_Ret ASSERT_NO_FATAL_FAILURE(Initialize()); const size_t pointerCount = MAX_POINTERS; - int32_t pointerIds[pointerCount]; + PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; + for (size_t i = 0; i < pointerCount; i++) { + pointerProperties[i].clear(); + pointerCoords[i].clear(); + } status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE, - 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords); + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(OK, status); status = mPublisher->sendDispatchSignal(); @@ -476,11 +500,15 @@ TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenBufferFull_ReturnsE ASSERT_NO_FATAL_FAILURE(Initialize()); const size_t pointerCount = MAX_POINTERS; - int32_t pointerIds[pointerCount]; + PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; + for (size_t i = 0; i < pointerCount; i++) { + pointerProperties[i].clear(); + pointerCoords[i].clear(); + } status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE, - 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords); + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(OK, status); for (int count = 1;; count++) { diff --git a/native/android/input.cpp b/native/android/input.cpp index ed26667..91671c3 100644 --- a/native/android/input.cpp +++ b/native/android/input.cpp @@ -92,6 +92,10 @@ int32_t AMotionEvent_getMetaState(const AInputEvent* motion_event) { return static_cast<const MotionEvent*>(motion_event)->getMetaState(); } +int32_t AMotionEvent_getButtonState(const AInputEvent* motion_event) { + return static_cast<const MotionEvent*>(motion_event)->getButtonState(); +} + int32_t AMotionEvent_getEdgeFlags(const AInputEvent* motion_event) { return reinterpret_cast<const MotionEvent*>(motion_event)->getEdgeFlags(); } @@ -128,6 +132,10 @@ int32_t AMotionEvent_getPointerId(const AInputEvent* motion_event, size_t pointe return static_cast<const MotionEvent*>(motion_event)->getPointerId(pointer_index); } +int32_t AMotionEvent_getToolType(const AInputEvent* motion_event, size_t pointer_index) { + return static_cast<const MotionEvent*>(motion_event)->getToolType(pointer_index); +} + float AMotionEvent_getRawX(const AInputEvent* motion_event, size_t pointer_index) { return static_cast<const MotionEvent*>(motion_event)->getRawX(pointer_index); } diff --git a/native/include/android/input.h b/native/include/android/input.h index f1738c6..26cac50 100644 --- a/native/include/android/input.h +++ b/native/include/android/input.h @@ -372,6 +372,7 @@ enum { AMOTION_EVENT_AXIS_WHEEL = 21, AMOTION_EVENT_AXIS_GAS = 22, AMOTION_EVENT_AXIS_BRAKE = 23, + AMOTION_EVENT_AXIS_DISTANCE = 24, AMOTION_EVENT_AXIS_GENERIC_1 = 32, AMOTION_EVENT_AXIS_GENERIC_2 = 33, AMOTION_EVENT_AXIS_GENERIC_3 = 34, @@ -394,6 +395,32 @@ enum { }; /* + * Constants that identify buttons that are associated with motion events. + * Refer to the documentation on the MotionEvent class for descriptions of each button. + */ +enum { + AMOTION_EVENT_BUTTON_PRIMARY = 1 << 0, + AMOTION_EVENT_BUTTON_SECONDARY = 1 << 1, + AMOTION_EVENT_BUTTON_TERTIARY = 1 << 2, + AMOTION_EVENT_BUTTON_BACK = 1 << 3, + AMOTION_EVENT_BUTTON_FORWARD = 1 << 4, + AMOTION_EVENT_BUTTON_ERASER = 1 << 5, +}; + +/* + * Constants that identify tool types. + * Refer to the documentation on the MotionEvent class for descriptions of each tool type. + */ +enum { + AMOTION_EVENT_TOOL_TYPE_UNKNOWN = 0, + AMOTION_EVENT_TOOL_TYPE_FINGER = 1, + AMOTION_EVENT_TOOL_TYPE_STYLUS = 2, + AMOTION_EVENT_TOOL_TYPE_MOUSE = 3, + AMOTION_EVENT_TOOL_TYPE_INDIRECT_FINGER = 4, + AMOTION_EVENT_TOOL_TYPE_INDIRECT_STYLUS = 5, +}; + +/* * Input sources. * * Refer to the documentation on android.view.InputDevice for more details about input sources @@ -417,6 +444,7 @@ enum { AINPUT_SOURCE_GAMEPAD = 0x00000400 | AINPUT_SOURCE_CLASS_BUTTON, AINPUT_SOURCE_TOUCHSCREEN = 0x00001000 | AINPUT_SOURCE_CLASS_POINTER, AINPUT_SOURCE_MOUSE = 0x00002000 | AINPUT_SOURCE_CLASS_POINTER, + AINPUT_SOURCE_STYLUS = 0x00004000 | AINPUT_SOURCE_CLASS_POINTER, AINPUT_SOURCE_TRACKBALL = 0x00010000 | AINPUT_SOURCE_CLASS_NAVIGATION, AINPUT_SOURCE_TOUCHPAD = 0x00100000 | AINPUT_SOURCE_CLASS_POSITION, AINPUT_SOURCE_JOYSTICK = 0x01000000 | AINPUT_SOURCE_CLASS_JOYSTICK, @@ -532,6 +560,9 @@ int32_t AMotionEvent_getFlags(const AInputEvent* motion_event); * event was generated. */ int32_t AMotionEvent_getMetaState(const AInputEvent* motion_event); +/* Get the button state of all buttons that are pressed. */ +int32_t AMotionEvent_getButtonState(const AInputEvent* motion_event); + /* Get a bitfield indicating which edges, if any, were touched by this motion event. * For touch events, clients can use this to determine if the user's finger was * touching the edge of the display. */ @@ -572,11 +603,16 @@ float AMotionEvent_getYPrecision(const AInputEvent* motion_event); size_t AMotionEvent_getPointerCount(const AInputEvent* motion_event); /* Get the pointer identifier associated with a particular pointer - * data index is this event. The identifier tells you the actual pointer + * data index in this event. The identifier tells you the actual pointer * number associated with the data, accounting for individual pointers * going up and down since the start of the current gesture. */ int32_t AMotionEvent_getPointerId(const AInputEvent* motion_event, size_t pointer_index); +/* Get the tool type of a pointer for the given pointer index. + * The tool type indicates the type of tool used to make contact such as a + * finger or stylus, if known. */ +int32_t AMotionEvent_getToolType(const AInputEvent* motion_event, size_t pointer_index); + /* Get the original raw X coordinate of this event. * For touch events on the screen, this is the original location of the event * on the screen, before it had been adjusted for the containing window diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp index 5bca7ee..8c535d6 100644 --- a/services/input/InputDispatcher.cpp +++ b/services/input/InputDispatcher.cpp @@ -150,7 +150,7 @@ static bool isValidMotionAction(int32_t action, size_t pointerCount) { } static bool validateMotionEvent(int32_t action, size_t pointerCount, - const int32_t* pointerIds) { + const PointerProperties* pointerProperties) { if (! isValidMotionAction(action, pointerCount)) { LOGE("Motion event has invalid action code 0x%x", action); return false; @@ -162,7 +162,7 @@ static bool validateMotionEvent(int32_t action, size_t pointerCount, } BitSet32 pointerIdBits; for (size_t i = 0; i < pointerCount; i++) { - int32_t id = pointerIds[i]; + int32_t id = pointerProperties[i].id; if (id < 0 || id > MAX_POINTER_ID) { LOGE("Motion event has invalid pointer id %d; value must be between 0 and %d", id, MAX_POINTER_ID); @@ -899,9 +899,10 @@ bool InputDispatcher::dispatchMotionLocked( MotionSample* nextSample = splitBatchAfterSample->next; MotionEntry* nextEntry = mAllocator.obtainMotionEntry(nextSample->eventTime, entry->deviceId, entry->source, entry->policyFlags, - entry->action, entry->flags, entry->metaState, entry->edgeFlags, + entry->action, entry->flags, + entry->metaState, entry->buttonState, entry->edgeFlags, entry->xPrecision, entry->yPrecision, entry->downTime, - entry->pointerCount, entry->pointerIds, nextSample->pointerCoords); + entry->pointerCount, entry->pointerProperties, nextSample->pointerCoords); if (nextSample != entry->lastSample) { nextEntry->firstSample.next = nextSample->next; nextEntry->lastSample = entry->lastSample; @@ -941,11 +942,13 @@ void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const M #if DEBUG_OUTBOUND_EVENT_DETAILS LOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " "action=0x%x, flags=0x%x, " - "metaState=0x%x, edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld", + "metaState=0x%x, buttonState=0x%x, " + "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld", prefix, entry->eventTime, entry->deviceId, entry->source, entry->policyFlags, entry->action, entry->flags, - entry->metaState, entry->edgeFlags, entry->xPrecision, entry->yPrecision, + entry->metaState, entry->buttonState, + entry->edgeFlags, entry->xPrecision, entry->yPrecision, entry->downTime); // Print the most recent sample that we have available, this may change due to batching. @@ -955,10 +958,12 @@ void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const M sampleCount += 1; } for (uint32_t i = 0; i < entry->pointerCount; i++) { - LOGD(" Pointer %d: id=%d, x=%f, y=%f, pressure=%f, size=%f, " + LOGD(" Pointer %d: id=%d, toolType=%d, " + "x=%f, y=%f, pressure=%f, size=%f, " "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " "orientation=%f", - i, entry->pointerIds[i], + i, entry->pointerProperties[i].id, + entry->pointerProperties[i].toolType, sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), @@ -1397,7 +1402,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, // Update the temporary touch state. BitSet32 pointerIds; if (isSplit) { - uint32_t pointerId = entry->pointerIds[pointerIndex]; + uint32_t pointerId = entry->pointerProperties[pointerIndex].id; pointerIds.markBit(pointerId); } mTempTouchState.addOrUpdateWindow(newTouchedWindow, targetFlags, pointerIds); @@ -1556,7 +1561,7 @@ Failed: // One pointer went up. if (isSplit) { int32_t pointerIndex = getMotionEventActionPointerIndex(action); - uint32_t pointerId = entry->pointerIds[pointerIndex]; + uint32_t pointerId = entry->pointerProperties[pointerIndex].id; for (size_t i = 0; i < mTempTouchState.windows.size(); ) { TouchedWindow& touchedWindow = mTempTouchState.windows.editItemAt(i); @@ -2010,10 +2015,13 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, // Publish the motion event and the first motion sample. status = connection->inputPublisher.publishMotionEvent(motionEntry->deviceId, - motionEntry->source, action, flags, motionEntry->edgeFlags, motionEntry->metaState, - xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision, + motionEntry->source, action, flags, motionEntry->edgeFlags, + motionEntry->metaState, motionEntry->buttonState, + xOffset, yOffset, + motionEntry->xPrecision, motionEntry->yPrecision, motionEntry->downTime, firstMotionSample->eventTime, - motionEntry->pointerCount, motionEntry->pointerIds, usingCoords); + motionEntry->pointerCount, motionEntry->pointerProperties, + usingCoords); if (status) { LOGE("channel '%s' ~ Could not publish motion event, " @@ -2027,7 +2035,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, // Append additional motion samples. MotionSample* nextMotionSample = firstMotionSample->next; for (; nextMotionSample != NULL; nextMotionSample = nextMotionSample->next) { - if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) != 0 && scaleFactor != 1.0f) { + if (usingCoords == scaledCoords) { for (size_t i = 0; i < motionEntry->pointerCount; i++) { scaledCoords[i] = nextMotionSample->pointerCoords[i]; scaledCoords[i].scale(scaleFactor); @@ -2305,7 +2313,7 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet LOG_ASSERT(pointerIds.value != 0); uint32_t splitPointerIndexMap[MAX_POINTERS]; - int32_t splitPointerIds[MAX_POINTERS]; + PointerProperties splitPointerProperties[MAX_POINTERS]; PointerCoords splitPointerCoords[MAX_POINTERS]; uint32_t originalPointerCount = originalMotionEntry->pointerCount; @@ -2313,10 +2321,12 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet for (uint32_t originalPointerIndex = 0; originalPointerIndex < originalPointerCount; originalPointerIndex++) { - int32_t pointerId = uint32_t(originalMotionEntry->pointerIds[originalPointerIndex]); + const PointerProperties& pointerProperties = + originalMotionEntry->pointerProperties[originalPointerIndex]; + uint32_t pointerId = uint32_t(pointerProperties.id); if (pointerIds.hasBit(pointerId)) { splitPointerIndexMap[splitPointerCount] = originalPointerIndex; - splitPointerIds[splitPointerCount] = pointerId; + splitPointerProperties[splitPointerCount].copyFrom(pointerProperties); splitPointerCoords[splitPointerCount].copyFrom( originalMotionEntry->firstSample.pointerCoords[originalPointerIndex]); splitPointerCount += 1; @@ -2341,7 +2351,9 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet if (maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN || maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { int32_t originalPointerIndex = getMotionEventActionPointerIndex(action); - int32_t pointerId = originalMotionEntry->pointerIds[originalPointerIndex]; + const PointerProperties& pointerProperties = + originalMotionEntry->pointerProperties[originalPointerIndex]; + uint32_t pointerId = uint32_t(pointerProperties.id); if (pointerIds.hasBit(pointerId)) { if (pointerIds.count() == 1) { // The first/last pointer went down/up. @@ -2350,7 +2362,7 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet } else { // A secondary pointer went down/up. uint32_t splitPointerIndex = 0; - while (pointerId != splitPointerIds[splitPointerIndex]) { + while (pointerId != uint32_t(splitPointerProperties[splitPointerIndex].id)) { splitPointerIndex += 1; } action = maskedAction | (splitPointerIndex @@ -2370,11 +2382,12 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet action, originalMotionEntry->flags, originalMotionEntry->metaState, + originalMotionEntry->buttonState, originalMotionEntry->edgeFlags, originalMotionEntry->xPrecision, originalMotionEntry->yPrecision, originalMotionEntry->downTime, - splitPointerCount, splitPointerIds, splitPointerCoords); + splitPointerCount, splitPointerProperties, splitPointerCoords); for (MotionSample* originalMotionSample = originalMotionEntry->firstSample.next; originalMotionSample != NULL; originalMotionSample = originalMotionSample->next) { @@ -2490,20 +2503,25 @@ void InputDispatcher::notifyKey(nsecs_t eventTime, int32_t deviceId, uint32_t so } void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t source, - uint32_t policyFlags, int32_t action, int32_t flags, int32_t metaState, int32_t edgeFlags, - uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords, + uint32_t policyFlags, int32_t action, int32_t flags, + int32_t metaState, int32_t buttonState, int32_t edgeFlags, + uint32_t pointerCount, const PointerProperties* pointerProperties, + const PointerCoords* pointerCoords, float xPrecision, float yPrecision, nsecs_t downTime) { #if DEBUG_INBOUND_EVENT_DETAILS LOGD("notifyMotion - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " - "action=0x%x, flags=0x%x, metaState=0x%x, edgeFlags=0x%x, " + "action=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, edgeFlags=0x%x, " "xPrecision=%f, yPrecision=%f, downTime=%lld", - eventTime, deviceId, source, policyFlags, action, flags, metaState, edgeFlags, + eventTime, deviceId, source, policyFlags, action, flags, + metaState, buttonState, edgeFlags, xPrecision, yPrecision, downTime); for (uint32_t i = 0; i < pointerCount; i++) { - LOGD(" Pointer %d: id=%d, x=%f, y=%f, pressure=%f, size=%f, " + LOGD(" Pointer %d: id=%d, toolType=%d, " + "x=%f, y=%f, pressure=%f, size=%f, " "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " "orientation=%f", - i, pointerIds[i], + i, pointerProperties[i].id, + pointerProperties[i].toolType, pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), @@ -2515,7 +2533,7 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); } #endif - if (! validateMotionEvent(action, pointerCount, pointerIds)) { + if (! validateMotionEvent(action, pointerCount, pointerProperties)) { return; } @@ -2530,9 +2548,10 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t mLock.unlock(); MotionEvent event; - event.initialize(deviceId, source, action, flags, edgeFlags, metaState, 0, 0, + event.initialize(deviceId, source, action, flags, edgeFlags, metaState, + buttonState, 0, 0, xPrecision, yPrecision, downTime, eventTime, - pointerCount, pointerIds, pointerCoords); + pointerCount, pointerProperties, pointerCoords); policyFlags |= POLICY_FLAG_FILTERED; if (!mPolicy->filterInputEvent(&event, policyFlags)) { @@ -2564,7 +2583,7 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t continue; } - if (!motionEntry->canAppendSamples(action, pointerCount, pointerIds)) { + if (!motionEntry->canAppendSamples(action, pointerCount, pointerProperties)) { // Last motion event in the queue for this device and source is // not compatible for appending new samples. Stop here. goto NoBatchingOrStreaming; @@ -2587,7 +2606,7 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t && mPendingEvent->type == EventEntry::TYPE_MOTION) { MotionEntry* motionEntry = static_cast<MotionEntry*>(mPendingEvent); if (motionEntry->deviceId == deviceId && motionEntry->source == source) { - if (!motionEntry->canAppendSamples(action, pointerCount, pointerIds)) { + if (!motionEntry->canAppendSamples(action, pointerCount, pointerProperties)) { // Pending motion event is for this device and source but it is // not compatible for appending new samples. Stop here. goto NoBatchingOrStreaming; @@ -2696,9 +2715,9 @@ NoBatchingOrStreaming:; // Just enqueue a new motion event. MotionEntry* newEntry = mAllocator.obtainMotionEntry(eventTime, - deviceId, source, policyFlags, action, flags, metaState, edgeFlags, + deviceId, source, policyFlags, action, flags, metaState, buttonState, edgeFlags, xPrecision, yPrecision, downTime, - pointerCount, pointerIds, pointerCoords); + pointerCount, pointerProperties, pointerCoords); needWake = enqueueInboundEventLocked(newEntry); mLock.unlock(); @@ -2801,8 +2820,8 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, const MotionEvent* motionEvent = static_cast<const MotionEvent*>(event); int32_t action = motionEvent->getAction(); size_t pointerCount = motionEvent->getPointerCount(); - const int32_t* pointerIds = motionEvent->getPointerIds(); - if (! validateMotionEvent(action, pointerCount, pointerIds)) { + const PointerProperties* pointerProperties = motionEvent->getPointerProperties(); + if (! validateMotionEvent(action, pointerCount, pointerProperties)) { return INPUT_EVENT_INJECTION_FAILED; } @@ -2817,10 +2836,11 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, MotionEntry* motionEntry = mAllocator.obtainMotionEntry(*sampleEventTimes, motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags, action, motionEvent->getFlags(), - motionEvent->getMetaState(), motionEvent->getEdgeFlags(), + motionEvent->getMetaState(), motionEvent->getButtonState(), + motionEvent->getEdgeFlags(), motionEvent->getXPrecision(), motionEvent->getYPrecision(), motionEvent->getDownTime(), uint32_t(pointerCount), - pointerIds, samplePointerCoords); + pointerProperties, samplePointerCoords); for (size_t i = motionEvent->getHistorySize(); i > 0; i--) { sampleEventTimes += 1; samplePointerCoords += pointerCount; @@ -3553,167 +3573,186 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( sp<Connection> connection = commandEntry->connection; bool handled = commandEntry->handled; + bool skipNext = false; if (!connection->outboundQueue.isEmpty()) { DispatchEntry* dispatchEntry = connection->outboundQueue.headSentinel.next; - if (dispatchEntry->inProgress - && dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) { - KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry); - if (!(keyEntry->flags & AKEY_EVENT_FLAG_FALLBACK)) { - // Get the fallback key state. - // Clear it out after dispatching the UP. - int32_t originalKeyCode = keyEntry->keyCode; - int32_t fallbackKeyCode = connection->inputState.getFallbackKey(originalKeyCode); - if (keyEntry->action == AKEY_EVENT_ACTION_UP) { - connection->inputState.removeFallbackKey(originalKeyCode); - } + if (dispatchEntry->inProgress) { + if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) { + KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry); + skipNext = afterKeyEventLockedInterruptible(connection, + dispatchEntry, keyEntry, handled); + } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) { + MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry); + skipNext = afterMotionEventLockedInterruptible(connection, + dispatchEntry, motionEntry, handled); + } + } + } - if (handled || !dispatchEntry->hasForegroundTarget()) { - // If the application handles the original key for which we previously - // generated a fallback or if the window is not a foreground window, - // then cancel the associated fallback key, if any. - if (fallbackKeyCode != -1) { - if (fallbackKeyCode != AKEYCODE_UNKNOWN) { - CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS, - "application handled the original non-fallback key " - "or is no longer a foreground target, " - "canceling previously dispatched fallback key"); - options.keyCode = fallbackKeyCode; - synthesizeCancelationEventsForConnectionLocked(connection, options); - } - connection->inputState.removeFallbackKey(originalKeyCode); - } - } else { - // If the application did not handle a non-fallback key, first check - // that we are in a good state to perform unhandled key event processing - // Then ask the policy what to do with it. - bool initialDown = keyEntry->action == AKEY_EVENT_ACTION_DOWN - && keyEntry->repeatCount == 0; - if (fallbackKeyCode == -1 && !initialDown) { + if (!skipNext) { + startNextDispatchCycleLocked(now(), connection); + } +} + +bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& connection, + DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled) { + if (!(keyEntry->flags & AKEY_EVENT_FLAG_FALLBACK)) { + // Get the fallback key state. + // Clear it out after dispatching the UP. + int32_t originalKeyCode = keyEntry->keyCode; + int32_t fallbackKeyCode = connection->inputState.getFallbackKey(originalKeyCode); + if (keyEntry->action == AKEY_EVENT_ACTION_UP) { + connection->inputState.removeFallbackKey(originalKeyCode); + } + + if (handled || !dispatchEntry->hasForegroundTarget()) { + // If the application handles the original key for which we previously + // generated a fallback or if the window is not a foreground window, + // then cancel the associated fallback key, if any. + if (fallbackKeyCode != -1) { + if (fallbackKeyCode != AKEYCODE_UNKNOWN) { + CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS, + "application handled the original non-fallback key " + "or is no longer a foreground target, " + "canceling previously dispatched fallback key"); + options.keyCode = fallbackKeyCode; + synthesizeCancelationEventsForConnectionLocked(connection, options); + } + connection->inputState.removeFallbackKey(originalKeyCode); + } + } else { + // If the application did not handle a non-fallback key, first check + // that we are in a good state to perform unhandled key event processing + // Then ask the policy what to do with it. + bool initialDown = keyEntry->action == AKEY_EVENT_ACTION_DOWN + && keyEntry->repeatCount == 0; + if (fallbackKeyCode == -1 && !initialDown) { #if DEBUG_OUTBOUND_EVENT_DETAILS - LOGD("Unhandled key event: Skipping unhandled key event processing " - "since this is not an initial down. " - "keyCode=%d, action=%d, repeatCount=%d", - originalKeyCode, keyEntry->action, keyEntry->repeatCount); + LOGD("Unhandled key event: Skipping unhandled key event processing " + "since this is not an initial down. " + "keyCode=%d, action=%d, repeatCount=%d", + originalKeyCode, keyEntry->action, keyEntry->repeatCount); #endif - goto SkipFallback; - } + return false; + } - // Dispatch the unhandled key to the policy. + // Dispatch the unhandled key to the policy. #if DEBUG_OUTBOUND_EVENT_DETAILS - LOGD("Unhandled key event: Asking policy to perform fallback action. " - "keyCode=%d, action=%d, repeatCount=%d", - keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount); + LOGD("Unhandled key event: Asking policy to perform fallback action. " + "keyCode=%d, action=%d, repeatCount=%d", + keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount); #endif - KeyEvent event; - initializeKeyEvent(&event, keyEntry); + KeyEvent event; + initializeKeyEvent(&event, keyEntry); - mLock.unlock(); + mLock.unlock(); - bool fallback = mPolicy->dispatchUnhandledKey(connection->inputWindowHandle, - &event, keyEntry->policyFlags, &event); + bool fallback = mPolicy->dispatchUnhandledKey(connection->inputWindowHandle, + &event, keyEntry->policyFlags, &event); - mLock.lock(); + mLock.lock(); - if (connection->status != Connection::STATUS_NORMAL) { - connection->inputState.removeFallbackKey(originalKeyCode); - return; - } + if (connection->status != Connection::STATUS_NORMAL) { + connection->inputState.removeFallbackKey(originalKeyCode); + return true; // skip next cycle + } - LOG_ASSERT(connection->outboundQueue.headSentinel.next == dispatchEntry); + LOG_ASSERT(connection->outboundQueue.headSentinel.next == dispatchEntry); - // Latch the fallback keycode for this key on an initial down. - // The fallback keycode cannot change at any other point in the lifecycle. - if (initialDown) { - if (fallback) { - fallbackKeyCode = event.getKeyCode(); - } else { - fallbackKeyCode = AKEYCODE_UNKNOWN; - } - connection->inputState.setFallbackKey(originalKeyCode, fallbackKeyCode); - } + // Latch the fallback keycode for this key on an initial down. + // The fallback keycode cannot change at any other point in the lifecycle. + if (initialDown) { + if (fallback) { + fallbackKeyCode = event.getKeyCode(); + } else { + fallbackKeyCode = AKEYCODE_UNKNOWN; + } + connection->inputState.setFallbackKey(originalKeyCode, fallbackKeyCode); + } - LOG_ASSERT(fallbackKeyCode != -1); + LOG_ASSERT(fallbackKeyCode != -1); - // Cancel the fallback key if the policy decides not to send it anymore. - // We will continue to dispatch the key to the policy but we will no - // longer dispatch a fallback key to the application. - if (fallbackKeyCode != AKEYCODE_UNKNOWN - && (!fallback || fallbackKeyCode != event.getKeyCode())) { + // Cancel the fallback key if the policy decides not to send it anymore. + // We will continue to dispatch the key to the policy but we will no + // longer dispatch a fallback key to the application. + if (fallbackKeyCode != AKEYCODE_UNKNOWN + && (!fallback || fallbackKeyCode != event.getKeyCode())) { #if DEBUG_OUTBOUND_EVENT_DETAILS - if (fallback) { - LOGD("Unhandled key event: Policy requested to send key %d" - "as a fallback for %d, but on the DOWN it had requested " - "to send %d instead. Fallback canceled.", - event.getKeyCode(), originalKeyCode, fallbackKeyCode); - } else { - LOGD("Unhandled key event: Policy did not request fallback for %d," - "but on the DOWN it had requested to send %d. " - "Fallback canceled.", - originalKeyCode, fallbackKeyCode); - } + if (fallback) { + LOGD("Unhandled key event: Policy requested to send key %d" + "as a fallback for %d, but on the DOWN it had requested " + "to send %d instead. Fallback canceled.", + event.getKeyCode(), originalKeyCode, fallbackKeyCode); + } else { + LOGD("Unhandled key event: Policy did not request fallback for %d," + "but on the DOWN it had requested to send %d. " + "Fallback canceled.", + originalKeyCode, fallbackKeyCode); + } #endif - CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS, - "canceling fallback, policy no longer desires it"); - options.keyCode = fallbackKeyCode; - synthesizeCancelationEventsForConnectionLocked(connection, options); + CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS, + "canceling fallback, policy no longer desires it"); + options.keyCode = fallbackKeyCode; + synthesizeCancelationEventsForConnectionLocked(connection, options); - fallback = false; - fallbackKeyCode = AKEYCODE_UNKNOWN; - if (keyEntry->action != AKEY_EVENT_ACTION_UP) { - connection->inputState.setFallbackKey(originalKeyCode, - fallbackKeyCode); - } - } + fallback = false; + fallbackKeyCode = AKEYCODE_UNKNOWN; + if (keyEntry->action != AKEY_EVENT_ACTION_UP) { + connection->inputState.setFallbackKey(originalKeyCode, + fallbackKeyCode); + } + } #if DEBUG_OUTBOUND_EVENT_DETAILS - { - String8 msg; - const KeyedVector<int32_t, int32_t>& fallbackKeys = - connection->inputState.getFallbackKeys(); - for (size_t i = 0; i < fallbackKeys.size(); i++) { - msg.appendFormat(", %d->%d", fallbackKeys.keyAt(i), - fallbackKeys.valueAt(i)); - } - LOGD("Unhandled key event: %d currently tracked fallback keys%s.", - fallbackKeys.size(), msg.string()); - } + { + String8 msg; + const KeyedVector<int32_t, int32_t>& fallbackKeys = + connection->inputState.getFallbackKeys(); + for (size_t i = 0; i < fallbackKeys.size(); i++) { + msg.appendFormat(", %d->%d", fallbackKeys.keyAt(i), + fallbackKeys.valueAt(i)); + } + LOGD("Unhandled key event: %d currently tracked fallback keys%s.", + fallbackKeys.size(), msg.string()); + } #endif - if (fallback) { - // Restart the dispatch cycle using the fallback key. - keyEntry->eventTime = event.getEventTime(); - keyEntry->deviceId = event.getDeviceId(); - keyEntry->source = event.getSource(); - keyEntry->flags = event.getFlags() | AKEY_EVENT_FLAG_FALLBACK; - keyEntry->keyCode = fallbackKeyCode; - keyEntry->scanCode = event.getScanCode(); - keyEntry->metaState = event.getMetaState(); - keyEntry->repeatCount = event.getRepeatCount(); - keyEntry->downTime = event.getDownTime(); - keyEntry->syntheticRepeat = false; + if (fallback) { + // Restart the dispatch cycle using the fallback key. + keyEntry->eventTime = event.getEventTime(); + keyEntry->deviceId = event.getDeviceId(); + keyEntry->source = event.getSource(); + keyEntry->flags = event.getFlags() | AKEY_EVENT_FLAG_FALLBACK; + keyEntry->keyCode = fallbackKeyCode; + keyEntry->scanCode = event.getScanCode(); + keyEntry->metaState = event.getMetaState(); + keyEntry->repeatCount = event.getRepeatCount(); + keyEntry->downTime = event.getDownTime(); + keyEntry->syntheticRepeat = false; #if DEBUG_OUTBOUND_EVENT_DETAILS - LOGD("Unhandled key event: Dispatching fallback key. " - "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x", - originalKeyCode, fallbackKeyCode, keyEntry->metaState); + LOGD("Unhandled key event: Dispatching fallback key. " + "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x", + originalKeyCode, fallbackKeyCode, keyEntry->metaState); #endif - dispatchEntry->inProgress = false; - startDispatchCycleLocked(now(), connection); - return; - } else { + dispatchEntry->inProgress = false; + startDispatchCycleLocked(now(), connection); + return true; // already started next cycle + } else { #if DEBUG_OUTBOUND_EVENT_DETAILS - LOGD("Unhandled key event: No fallback key."); + LOGD("Unhandled key event: No fallback key."); #endif - } - } } } } + return false; +} -SkipFallback: - startNextDispatchCycleLocked(now(), connection); +bool InputDispatcher::afterMotionEventLockedInterruptible(const sp<Connection>& connection, + DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled) { + return false; } void InputDispatcher::doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) { @@ -3817,9 +3856,10 @@ InputDispatcher::KeyEntry* InputDispatcher::Allocator::obtainKeyEntry(nsecs_t ev InputDispatcher::MotionEntry* InputDispatcher::Allocator::obtainMotionEntry(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, - int32_t metaState, int32_t edgeFlags, float xPrecision, float yPrecision, + int32_t metaState, int32_t buttonState, + int32_t edgeFlags, float xPrecision, float yPrecision, nsecs_t downTime, uint32_t pointerCount, - const int32_t* pointerIds, const PointerCoords* pointerCoords) { + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { MotionEntry* entry = mMotionEntryPool.alloc(); initializeEventEntry(entry, EventEntry::TYPE_MOTION, eventTime, policyFlags); @@ -3829,6 +3869,7 @@ InputDispatcher::MotionEntry* InputDispatcher::Allocator::obtainMotionEntry(nsec entry->action = action; entry->flags = flags; entry->metaState = metaState; + entry->buttonState = buttonState; entry->edgeFlags = edgeFlags; entry->xPrecision = xPrecision; entry->yPrecision = yPrecision; @@ -3839,7 +3880,7 @@ InputDispatcher::MotionEntry* InputDispatcher::Allocator::obtainMotionEntry(nsec entry->firstSample.next = NULL; entry->lastSample = & entry->firstSample; for (uint32_t i = 0; i < pointerCount; i++) { - entry->pointerIds[i] = pointerIds[i]; + entry->pointerProperties[i].copyFrom(pointerProperties[i]); entry->firstSample.pointerCoords[i].copyFrom(pointerCoords[i]); } return entry; @@ -3977,14 +4018,14 @@ uint32_t InputDispatcher::MotionEntry::countSamples() const { } bool InputDispatcher::MotionEntry::canAppendSamples(int32_t action, uint32_t pointerCount, - const int32_t* pointerIds) const { + const PointerProperties* pointerProperties) const { if (this->action != action || this->pointerCount != pointerCount || this->isInjected()) { return false; } for (uint32_t i = 0; i < pointerCount; i++) { - if (this->pointerIds[i] != pointerIds[i]) { + if (this->pointerProperties[i] != pointerProperties[i]) { return false; } } @@ -4114,7 +4155,7 @@ Found: void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry* entry) { pointerCount = entry->pointerCount; for (uint32_t i = 0; i < entry->pointerCount; i++) { - pointerIds[i] = entry->pointerIds[i]; + pointerProperties[i].copyFrom(entry->pointerProperties[i]); pointerCoords[i].copyFrom(entry->lastSample->pointerCoords[i]); } } @@ -4143,9 +4184,9 @@ void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTim memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL, - 0, 0, 0, + 0, 0, 0, 0, memento.xPrecision, memento.yPrecision, memento.downTime, - memento.pointerCount, memento.pointerIds, memento.pointerCoords)); + memento.pointerCount, memento.pointerProperties, memento.pointerCoords)); mMotionMementos.removeAt(i); } else { i += 1; diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h index 96ece32..9ac5b75 100644 --- a/services/input/InputDispatcher.h +++ b/services/input/InputDispatcher.h @@ -263,8 +263,9 @@ public: int32_t scanCode, int32_t metaState, nsecs_t downTime) = 0; virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, - int32_t metaState, int32_t edgeFlags, - uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords, + int32_t metaState, int32_t buttonState, int32_t edgeFlags, + uint32_t pointerCount, const PointerProperties* pointerProperties, + const PointerCoords* pointerCoords, float xPrecision, float yPrecision, nsecs_t downTime) = 0; virtual void notifySwitch(nsecs_t when, int32_t switchCode, int32_t switchValue, uint32_t policyFlags) = 0; @@ -358,8 +359,9 @@ public: int32_t scanCode, int32_t metaState, nsecs_t downTime); virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, - int32_t metaState, int32_t edgeFlags, - uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords, + int32_t metaState, int32_t buttonState, int32_t edgeFlags, + uint32_t pointerCount, const PointerProperties* pointerProperties, + const PointerCoords* pointerCoords, float xPrecision, float yPrecision, nsecs_t downTime); virtual void notifySwitch(nsecs_t when, int32_t switchCode, int32_t switchValue, uint32_t policyFlags) ; @@ -454,12 +456,13 @@ private: int32_t action; int32_t flags; int32_t metaState; + int32_t buttonState; int32_t edgeFlags; float xPrecision; float yPrecision; nsecs_t downTime; uint32_t pointerCount; - int32_t pointerIds[MAX_POINTERS]; + PointerProperties pointerProperties[MAX_POINTERS]; // Linked list of motion samples associated with this motion event. MotionSample firstSample; @@ -469,7 +472,7 @@ private: // Checks whether we can append samples, assuming the device id and source are the same. bool canAppendSamples(int32_t action, uint32_t pointerCount, - const int32_t* pointerIds) const; + const PointerProperties* pointerProperties) const; }; // Tracks the progress of dispatching a particular event to a particular connection. @@ -602,10 +605,10 @@ private: int32_t repeatCount, nsecs_t downTime); MotionEntry* obtainMotionEntry(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, - int32_t flags, int32_t metaState, int32_t edgeFlags, + int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, float xPrecision, float yPrecision, nsecs_t downTime, uint32_t pointerCount, - const int32_t* pointerIds, const PointerCoords* pointerCoords); + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); DispatchEntry* obtainDispatchEntry(EventEntry* eventEntry, int32_t targetFlags, float xOffset, float yOffset, float scaleFactor); CommandEntry* obtainCommandEntry(Command command); @@ -721,7 +724,7 @@ private: float yPrecision; nsecs_t downTime; uint32_t pointerCount; - int32_t pointerIds[MAX_POINTERS]; + PointerProperties pointerProperties[MAX_POINTERS]; PointerCoords pointerCoords[MAX_POINTERS]; bool hovering; @@ -1053,6 +1056,10 @@ private: void doNotifyANRLockedInterruptible(CommandEntry* commandEntry); void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry); void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry); + bool afterKeyEventLockedInterruptible(const sp<Connection>& connection, + DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled); + bool afterMotionEventLockedInterruptible(const sp<Connection>& connection, + DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled); void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry); void initializeKeyEvent(KeyEvent* event, const KeyEntry* entry); diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index 98b3526..6003207 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -208,23 +208,32 @@ static uint32_t getButtonStateForScanCode(int32_t scanCode) { // Currently all buttons are mapped to the primary button. switch (scanCode) { case BTN_LEFT: + return AMOTION_EVENT_BUTTON_PRIMARY; case BTN_RIGHT: + return AMOTION_EVENT_BUTTON_SECONDARY; case BTN_MIDDLE: + return AMOTION_EVENT_BUTTON_TERTIARY; case BTN_SIDE: + return AMOTION_EVENT_BUTTON_BACK; case BTN_EXTRA: + return AMOTION_EVENT_BUTTON_FORWARD; case BTN_FORWARD: + return AMOTION_EVENT_BUTTON_FORWARD; case BTN_BACK: + return AMOTION_EVENT_BUTTON_BACK; case BTN_TASK: - return BUTTON_STATE_PRIMARY; default: return 0; } } // Returns true if the pointer should be reported as being down given the specified -// button states. -static bool isPointerDown(uint32_t buttonState) { - return buttonState & BUTTON_STATE_PRIMARY; +// button states. This determines whether the event is reported as a touch event. +static bool isPointerDown(int32_t buttonState) { + return buttonState & + (AMOTION_EVENT_BUTTON_PRIMARY | AMOTION_EVENT_BUTTON_SECONDARY + | AMOTION_EVENT_BUTTON_TERTIARY + | AMOTION_EVENT_BUTTON_ERASER); } static int32_t calculateEdgeFlagsUsingPointerBounds( @@ -273,6 +282,33 @@ static float calculateCommonVector(float a, float b) { } } +static void synthesizeButtonKey(InputReaderContext* context, int32_t action, + nsecs_t when, int32_t deviceId, uint32_t source, + uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState, + int32_t buttonState, int32_t keyCode) { + if ( + (action == AKEY_EVENT_ACTION_DOWN + && !(lastButtonState & buttonState) + && (currentButtonState & buttonState)) + || (action == AKEY_EVENT_ACTION_UP + && (lastButtonState & buttonState) + && !(currentButtonState & buttonState))) { + context->getDispatcher()->notifyKey(when, deviceId, source, policyFlags, + action, 0, keyCode, 0, context->getGlobalMetaState(), when); + } +} + +static void synthesizeButtonKeys(InputReaderContext* context, int32_t action, + nsecs_t when, int32_t deviceId, uint32_t source, + uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState) { + synthesizeButtonKey(context, action, when, deviceId, source, policyFlags, + lastButtonState, currentButtonState, + AMOTION_EVENT_BUTTON_BACK, AKEYCODE_BACK); + synthesizeButtonKey(context, action, when, deviceId, source, policyFlags, + lastButtonState, currentButtonState, + AMOTION_EVENT_BUTTON_FORWARD, AKEYCODE_FORWARD); +} + // --- InputReader --- @@ -1443,7 +1479,7 @@ void CursorInputMapper::initializeLocked() { void CursorInputMapper::reset() { for (;;) { - uint32_t buttonState; + int32_t buttonState; { // acquire lock AutoMutex _l(mLock); @@ -1469,7 +1505,7 @@ void CursorInputMapper::reset() { void CursorInputMapper::process(const RawEvent* rawEvent) { switch (rawEvent->type) { case EV_KEY: { - uint32_t buttonState = getButtonStateForScanCode(rawEvent->scanCode); + int32_t buttonState = getButtonStateForScanCode(rawEvent->scanCode); if (buttonState) { if (rawEvent->value) { mAccumulator.buttonDown = buttonState; @@ -1527,12 +1563,16 @@ void CursorInputMapper::sync(nsecs_t when) { int32_t motionEventAction; int32_t motionEventEdgeFlags; + int32_t lastButtonState, currentButtonState; + PointerProperties pointerProperties; PointerCoords pointerCoords; nsecs_t downTime; float vscroll, hscroll; { // acquire lock AutoMutex _l(mLock); + lastButtonState = mLocked.buttonState; + bool down, downChanged; bool wasDown = isPointerDown(mLocked.buttonState); bool buttonsChanged = fields & Accumulator::FIELD_BUTTONS; @@ -1555,6 +1595,8 @@ void CursorInputMapper::sync(nsecs_t when) { downChanged = false; } + currentButtonState = mLocked.buttonState; + downTime = mLocked.downTime; float deltaX = fields & Accumulator::FIELD_REL_X ? mAccumulator.relX * mXScale : 0.0f; float deltaY = fields & Accumulator::FIELD_REL_Y ? mAccumulator.relY * mYScale : 0.0f; @@ -1598,10 +1640,14 @@ void CursorInputMapper::sync(nsecs_t when) { } } - pointerCoords.clear(); - motionEventEdgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE; + pointerProperties.clear(); + pointerProperties.id = 0; + pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_MOUSE; + + pointerCoords.clear(); + if (mHaveVWheel && (fields & Accumulator::FIELD_REL_WHEEL)) { vscroll = mAccumulator.relWheel; } else { @@ -1656,18 +1702,23 @@ void CursorInputMapper::sync(nsecs_t when) { policyFlags |= POLICY_FLAG_WAKE_DROPPED; } + // Synthesize key down from buttons if needed. + synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, + policyFlags, lastButtonState, currentButtonState); + + // Send motion event. int32_t metaState = mContext->getGlobalMetaState(); - int32_t pointerId = 0; getDispatcher()->notifyMotion(when, getDeviceId(), mSource, policyFlags, - motionEventAction, 0, metaState, motionEventEdgeFlags, - 1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime); + motionEventAction, 0, metaState, currentButtonState, motionEventEdgeFlags, + 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime); // Send hover move after UP to tell the application that the mouse is hovering now. if (motionEventAction == AMOTION_EVENT_ACTION_UP && mPointerController != NULL) { getDispatcher()->notifyMotion(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, - 1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime); + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, + metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE, + 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime); } // Send scroll events. @@ -1676,10 +1727,15 @@ void CursorInputMapper::sync(nsecs_t when) { pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); getDispatcher()->notifyMotion(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, - 1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime); + AMOTION_EVENT_ACTION_SCROLL, 0, metaState, currentButtonState, + AMOTION_EVENT_EDGE_FLAG_NONE, + 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime); } + // Synthesize key up from buttons if needed. + synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, + policyFlags, lastButtonState, currentButtonState); + mAccumulator.clear(); } @@ -2766,6 +2822,11 @@ void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) { } } + // Synthesize key down from buttons if needed. + synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mTouchSource, + policyFlags, mLastTouch.buttonState, mCurrentTouch.buttonState); + + // Send motion events. TouchResult touchResult; if (mLastTouch.pointerCount == 0 && mCurrentTouch.pointerCount == 0 && mLastTouch.buttonState == mCurrentTouch.buttonState) { @@ -2783,6 +2844,10 @@ void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) { } } + // Synthesize key up from buttons if needed. + synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mTouchSource, + policyFlags, mLastTouch.buttonState, mCurrentTouch.buttonState); + // Copy current touch to last touch in preparation for the next cycle. // Keep the button state so we can track edge-triggered button state changes. if (touchResult == DROP_STROKE) { @@ -2949,14 +3014,17 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { // Dispatch motions. BitSet32 currentIdBits = mCurrentTouch.idBits; BitSet32 lastIdBits = mLastTouch.idBits; - uint32_t metaState = getContext()->getGlobalMetaState(); + int32_t metaState = getContext()->getGlobalMetaState(); + int32_t buttonState = mCurrentTouch.buttonState; if (currentIdBits == lastIdBits) { // No pointer id changes so this is a move event. // The dispatcher takes care of batching moves so we don't have to deal with that here. dispatchMotion(when, policyFlags, mTouchSource, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, - mCurrentTouchCoords, mCurrentTouch.idToIndex, currentIdBits, -1, + AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, + AMOTION_EVENT_EDGE_FLAG_NONE, + mCurrentTouchProperties, mCurrentTouchCoords, + mCurrentTouch.idToIndex, currentIdBits, -1, xPrecision, yPrecision, mDownTime); } else { // There may be pointers going up and pointers going down and pointers moving @@ -2968,10 +3036,13 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { // Update last coordinates of pointers that have moved so that we observe the new // pointer positions at the same time as other pointers that have just gone up. - bool moveNeeded = updateMovedPointerCoords( - mCurrentTouchCoords, mCurrentTouch.idToIndex, - mLastTouchCoords, mLastTouch.idToIndex, + bool moveNeeded = updateMovedPointers( + mCurrentTouchProperties, mCurrentTouchCoords, mCurrentTouch.idToIndex, + mLastTouchProperties, mLastTouchCoords, mLastTouch.idToIndex, moveIdBits); + if (buttonState != mLastTouch.buttonState) { + moveNeeded = true; + } // Dispatch pointer up events. while (!upIdBits.isEmpty()) { @@ -2979,8 +3050,9 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { upIdBits.clearBit(upId); dispatchMotion(when, policyFlags, mTouchSource, - AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, 0, - mLastTouchCoords, mLastTouch.idToIndex, dispatchedIdBits, upId, + AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, buttonState, 0, + mLastTouchProperties, mLastTouchCoords, + mLastTouch.idToIndex, dispatchedIdBits, upId, xPrecision, yPrecision, mDownTime); dispatchedIdBits.clearBit(upId); } @@ -2991,8 +3063,9 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { if (moveNeeded) { LOG_ASSERT(moveIdBits.value == dispatchedIdBits.value); dispatchMotion(when, policyFlags, mTouchSource, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, 0, - mCurrentTouchCoords, mCurrentTouch.idToIndex, dispatchedIdBits, -1, + AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, 0, + mCurrentTouchProperties, mCurrentTouchCoords, + mCurrentTouch.idToIndex, dispatchedIdBits, -1, xPrecision, yPrecision, mDownTime); } @@ -3011,14 +3084,16 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { } dispatchMotion(when, policyFlags, mTouchSource, - AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, edgeFlags, - mCurrentTouchCoords, mCurrentTouch.idToIndex, dispatchedIdBits, downId, + AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, edgeFlags, + mCurrentTouchProperties, mCurrentTouchCoords, + mCurrentTouch.idToIndex, dispatchedIdBits, downId, xPrecision, yPrecision, mDownTime); } } // Update state for next time. for (uint32_t i = 0; i < currentPointerCount; i++) { + mLastTouchProperties[i].copyFrom(mCurrentTouchProperties[i]); mLastTouchCoords[i].copyFrom(mCurrentTouchCoords[i]); } } @@ -3214,6 +3289,12 @@ void TouchInputMapper::prepareTouches(int32_t* outEdgeFlags, out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor); out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor); out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation); + + // Write output properties. + PointerProperties& properties = mCurrentTouchProperties[i]; + properties.clear(); + properties.id = mCurrentTouch.pointers[i].id; + properties.toolType = getTouchToolType(mCurrentTouch.pointers[i].isStylus); } // Check edge flags by looking only at the first pointer since the flags are @@ -3265,7 +3346,8 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag } // Send events! - uint32_t metaState = getContext()->getGlobalMetaState(); + int32_t metaState = getContext()->getGlobalMetaState(); + int32_t buttonState = mCurrentTouch.buttonState; // Update last coordinates of pointers that have moved so that we observe the new // pointer positions at the same time as other pointers that have just gone up. @@ -3281,10 +3363,14 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag && !mPointerGesture.currentGestureIdBits.isEmpty()) { BitSet32 movedGestureIdBits(mPointerGesture.currentGestureIdBits.value & mPointerGesture.lastGestureIdBits.value); - moveNeeded = updateMovedPointerCoords( + moveNeeded = updateMovedPointers(mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, + mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, movedGestureIdBits); + if (buttonState != mLastTouch.buttonState) { + moveNeeded = true; + } } // Send motion events for all pointers that went up or were canceled. @@ -3292,7 +3378,9 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag if (!dispatchedGestureIdBits.isEmpty()) { if (cancelPreviousGesture) { dispatchMotion(when, policyFlags, mPointerSource, - AMOTION_EVENT_ACTION_CANCEL, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, + AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState, + AMOTION_EVENT_EDGE_FLAG_NONE, + mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, -1, 0, 0, mPointerGesture.downTime); @@ -3312,7 +3400,8 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag dispatchMotion(when, policyFlags, mPointerSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, - metaState, AMOTION_EVENT_EDGE_FLAG_NONE, + metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, + mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, id, 0, 0, mPointerGesture.downTime); @@ -3325,7 +3414,8 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag // Send motion events for all pointers that moved. if (moveNeeded) { dispatchMotion(when, policyFlags, mPointerSource, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, + AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, + mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, -1, 0, 0, mPointerGesture.downTime); @@ -3352,7 +3442,8 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag } dispatchMotion(when, policyFlags, mPointerSource, - AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, edgeFlags, + AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, edgeFlags, + mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, id, 0, 0, mPointerGesture.downTime); @@ -3362,7 +3453,9 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag // Send motion events for hover. if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) { dispatchMotion(when, policyFlags, mPointerSource, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, + metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, + mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, mPointerGesture.currentGestureIdBits, -1, 0, 0, mPointerGesture.downTime); @@ -3378,6 +3471,8 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag uint32_t id = idBits.firstMarkedBit(); idBits.clearBit(id); uint32_t index = mPointerGesture.currentGestureIdToIndex[id]; + mPointerGesture.lastGestureProperties[index].copyFrom( + mPointerGesture.currentGestureProperties[index]); mPointerGesture.lastGestureCoords[index].copyFrom( mPointerGesture.currentGestureCoords[index]); mPointerGesture.lastGestureIdToIndex[id] = index; @@ -3413,8 +3508,6 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; mPointerGesture.currentGestureIdBits.clear(); - mPointerController->setButtonState(0); - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_NEUTRAL; mPointerGesture.spotIdBits.clear(); @@ -3509,8 +3602,6 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureMode = PointerGesture::QUIET; mPointerGesture.currentGestureIdBits.clear(); - mPointerController->setButtonState(0); - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_NEUTRAL; mPointerGesture.spotIdBits.clear(); @@ -3591,13 +3682,15 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureIdBits.clear(); mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; + mPointerGesture.currentGestureProperties[0].clear(); + mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; + mPointerGesture.currentGestureProperties[0].toolType = + AMOTION_EVENT_TOOL_TYPE_INDIRECT_FINGER; mPointerGesture.currentGestureCoords[0].clear(); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - mPointerController->setButtonState(BUTTON_STATE_PRIMARY); - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { if (activeTouchId >= 0) { // Collapse all spots into one point at the pointer location. @@ -3648,6 +3741,11 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.activeGestureId); mPointerGesture.currentGestureIdToIndex[ mPointerGesture.activeGestureId] = 0; + mPointerGesture.currentGestureProperties[0].clear(); + mPointerGesture.currentGestureProperties[0].id = + mPointerGesture.activeGestureId; + mPointerGesture.currentGestureProperties[0].toolType = + AMOTION_EVENT_TOOL_TYPE_INDIRECT_FINGER; mPointerGesture.currentGestureCoords[0].clear(); mPointerGesture.currentGestureCoords[0].setAxisValue( AMOTION_EVENT_AXIS_X, mPointerGesture.tapX); @@ -3656,8 +3754,6 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureCoords[0].setAxisValue( AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - mPointerController->setButtonState(BUTTON_STATE_PRIMARY); - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_TAP; mPointerGesture.spotIdBits.clear(); @@ -3691,8 +3787,6 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; mPointerGesture.currentGestureIdBits.clear(); - mPointerController->setButtonState(0); - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_NEUTRAL; mPointerGesture.spotIdBits.clear(); @@ -3767,14 +3861,16 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureIdBits.clear(); mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; + mPointerGesture.currentGestureProperties[0].clear(); + mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; + mPointerGesture.currentGestureProperties[0].toolType = + AMOTION_EVENT_TOOL_TYPE_INDIRECT_FINGER; mPointerGesture.currentGestureCoords[0].clear(); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f); - mPointerController->setButtonState(down ? BUTTON_STATE_PRIMARY : 0); - if (mLastTouch.pointerCount == 0 && mCurrentTouch.pointerCount != 0) { mPointerGesture.resetTap(); mPointerGesture.tapDownTime = when; @@ -3994,6 +4090,10 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureIdBits.clear(); mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; + mPointerGesture.currentGestureProperties[0].clear(); + mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; + mPointerGesture.currentGestureProperties[0].toolType = + AMOTION_EVENT_TOOL_TYPE_INDIRECT_FINGER; mPointerGesture.currentGestureCoords[0].clear(); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, mPointerGesture.referenceGestureX); @@ -4001,8 +4101,6 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.referenceGestureY); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - mPointerController->setButtonState(BUTTON_STATE_PRIMARY); - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_PRESS; } @@ -4018,6 +4116,10 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureIdBits.clear(); mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; + mPointerGesture.currentGestureProperties[0].clear(); + mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; + mPointerGesture.currentGestureProperties[0].toolType = + AMOTION_EVENT_TOOL_TYPE_INDIRECT_FINGER; mPointerGesture.currentGestureCoords[0].clear(); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, mPointerGesture.referenceGestureX); @@ -4025,8 +4127,6 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.referenceGestureY); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - mPointerController->setButtonState(0); // touch is not actually following the pointer - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_SWIPE; } @@ -4110,6 +4210,10 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, float y = (mCurrentTouch.pointers[i].y - mPointerGesture.referenceTouchY) * mLocked.pointerGestureYZoomScale + mPointerGesture.referenceGestureY; + mPointerGesture.currentGestureProperties[i].clear(); + mPointerGesture.currentGestureProperties[i].id = gestureId; + mPointerGesture.currentGestureProperties[i].toolType = + AMOTION_EVENT_TOOL_TYPE_INDIRECT_FINGER; mPointerGesture.currentGestureCoords[i].clear(); mPointerGesture.currentGestureCoords[i].setAxisValue( AMOTION_EVENT_AXIS_X, x); @@ -4128,8 +4232,6 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, #endif } - mPointerController->setButtonState(0); // touch is not actually following the pointer - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { mPointerGesture.spotGesture = PointerControllerInterface::SPOT_GESTURE_FREEFORM; } @@ -4159,6 +4261,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } } + mPointerController->setButtonState(mCurrentTouch.buttonState); + #if DEBUG_GESTURES LOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, " "currentGestureMode=%d, currentGestureIdBits=0x%08x, " @@ -4170,9 +4274,12 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, uint32_t id = idBits.firstMarkedBit(); idBits.clearBit(id); uint32_t index = mPointerGesture.currentGestureIdToIndex[id]; + const PointerProperties& properties = mPointerGesture.currentGestureProperties[index]; const PointerCoords& coords = mPointerGesture.currentGestureCoords[index]; - LOGD(" currentGesture[%d]: index=%d, x=%0.3f, y=%0.3f, pressure=%0.3f", - id, index, coords.getAxisValue(AMOTION_EVENT_AXIS_X), + LOGD(" currentGesture[%d]: index=%d, toolType=%d, " + "x=%0.3f, y=%0.3f, pressure=%0.3f", + id, index, properties.toolType, + coords.getAxisValue(AMOTION_EVENT_AXIS_X), coords.getAxisValue(AMOTION_EVENT_AXIS_Y), coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); } @@ -4180,9 +4287,12 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, uint32_t id = idBits.firstMarkedBit(); idBits.clearBit(id); uint32_t index = mPointerGesture.lastGestureIdToIndex[id]; + const PointerProperties& properties = mPointerGesture.lastGestureProperties[index]; const PointerCoords& coords = mPointerGesture.lastGestureCoords[index]; - LOGD(" lastGesture[%d]: index=%d, x=%0.3f, y=%0.3f, pressure=%0.3f", - id, index, coords.getAxisValue(AMOTION_EVENT_AXIS_X), + LOGD(" lastGesture[%d]: index=%d, toolType=%d, " + "x=%0.3f, y=%0.3f, pressure=%0.3f", + id, index, properties.toolType, + coords.getAxisValue(AMOTION_EVENT_AXIS_X), coords.getAxisValue(AMOTION_EVENT_AXIS_Y), coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); } @@ -4196,17 +4306,18 @@ void TouchInputMapper::moveSpotsLocked() { } void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, - int32_t action, int32_t flags, uint32_t metaState, int32_t edgeFlags, - const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits, + int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, + const PointerProperties* properties, const PointerCoords* coords, + const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) { PointerCoords pointerCoords[MAX_POINTERS]; - int32_t pointerIds[MAX_POINTERS]; + PointerProperties pointerProperties[MAX_POINTERS]; uint32_t pointerCount = 0; while (!idBits.isEmpty()) { uint32_t id = idBits.firstMarkedBit(); idBits.clearBit(id); uint32_t index = idToIndex[id]; - pointerIds[pointerCount] = id; + pointerProperties[pointerCount].copyFrom(properties[index]); pointerCoords[pointerCount].copyFrom(coords[index]); if (changedId >= 0 && id == uint32_t(changedId)) { @@ -4233,13 +4344,14 @@ void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32 } getDispatcher()->notifyMotion(when, getDeviceId(), source, policyFlags, - action, flags, metaState, edgeFlags, - pointerCount, pointerIds, pointerCoords, xPrecision, yPrecision, downTime); + action, flags, metaState, buttonState, edgeFlags, + pointerCount, pointerProperties, pointerCoords, xPrecision, yPrecision, downTime); } -bool TouchInputMapper::updateMovedPointerCoords( +bool TouchInputMapper::updateMovedPointers(const PointerProperties* inProperties, const PointerCoords* inCoords, const uint32_t* inIdToIndex, - PointerCoords* outCoords, const uint32_t* outIdToIndex, BitSet32 idBits) const { + PointerProperties* outProperties, PointerCoords* outCoords, const uint32_t* outIdToIndex, + BitSet32 idBits) const { bool changed = false; while (!idBits.isEmpty()) { uint32_t id = idBits.firstMarkedBit(); @@ -4247,9 +4359,17 @@ bool TouchInputMapper::updateMovedPointerCoords( uint32_t inIndex = inIdToIndex[id]; uint32_t outIndex = outIdToIndex[id]; + + const PointerProperties& curInProperties = inProperties[inIndex]; const PointerCoords& curInCoords = inCoords[inIndex]; + PointerProperties& curOutProperties = outProperties[outIndex]; PointerCoords& curOutCoords = outCoords[outIndex]; + if (curInProperties != curOutProperties) { + curOutProperties.copyFrom(curInProperties); + changed = true; + } + if (curInCoords != curOutCoords) { curOutCoords.copyFrom(curInCoords); changed = true; @@ -4267,6 +4387,15 @@ void TouchInputMapper::fadePointer() { } // release lock } +int32_t TouchInputMapper::getTouchToolType(bool isStylus) const { + if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) { + return isStylus ? AMOTION_EVENT_TOOL_TYPE_STYLUS : AMOTION_EVENT_TOOL_TYPE_FINGER; + } else { + return isStylus ? AMOTION_EVENT_TOOL_TYPE_INDIRECT_STYLUS + : AMOTION_EVENT_TOOL_TYPE_INDIRECT_FINGER; + } +} + bool TouchInputMapper::isPointInsideSurfaceLocked(int32_t x, int32_t y) { return x >= mRawAxes.x.minValue && x <= mRawAxes.x.maxValue && y >= mRawAxes.y.minValue && y <= mRawAxes.y.maxValue; @@ -4927,7 +5056,7 @@ void SingleTouchInputMapper::process(const RawEvent* rawEvent) { break; default: if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) { - uint32_t buttonState = getButtonStateForScanCode(rawEvent->scanCode); + int32_t buttonState = getButtonStateForScanCode(rawEvent->scanCode); if (buttonState) { if (rawEvent->value) { mAccumulator.buttonDown |= buttonState; @@ -5015,6 +5144,7 @@ void SingleTouchInputMapper::sync(nsecs_t when) { mCurrentTouch.pointers[0].toolMajor = mToolWidth; mCurrentTouch.pointers[0].toolMinor = mToolWidth; mCurrentTouch.pointers[0].orientation = 0; + mCurrentTouch.pointers[0].isStylus = false; // TODO: Set stylus mCurrentTouch.idToIndex[0] = 0; mCurrentTouch.idBits.markBit(0); mCurrentTouch.buttonState = mButtonState; @@ -5060,7 +5190,7 @@ void MultiTouchInputMapper::process(const RawEvent* rawEvent) { switch (rawEvent->type) { case EV_KEY: { if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) { - uint32_t buttonState = getButtonStateForScanCode(rawEvent->scanCode); + int32_t buttonState = getButtonStateForScanCode(rawEvent->scanCode); if (buttonState) { if (rawEvent->value) { mAccumulator.buttonDown |= buttonState; @@ -5221,6 +5351,8 @@ void MultiTouchInputMapper::sync(nsecs_t when) { outPointer.orientation = 0; } + outPointer.isStylus = false; // TODO: Handle stylus + // Assign pointer id using tracking id if available. if (havePointerIds) { if (fields & Accumulator::FIELD_ABS_MT_TRACKING_ID) { @@ -5531,6 +5663,12 @@ void JoystickInputMapper::sync(nsecs_t when, bool force) { } int32_t metaState = mContext->getGlobalMetaState(); + int32_t buttonState = 0; + + PointerProperties pointerProperties; + pointerProperties.clear(); + pointerProperties.id = 0; + pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; PointerCoords pointerCoords; pointerCoords.clear(); @@ -5550,10 +5688,9 @@ void JoystickInputMapper::sync(nsecs_t when, bool force) { // TODO: Use the input device configuration to control this behavior more finely. uint32_t policyFlags = 0; - int32_t pointerId = 0; getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, policyFlags, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, - 1, &pointerId, &pointerCoords, 0, 0, 0); + AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, + 1, &pointerProperties, &pointerCoords, 0, 0, 0); } bool JoystickInputMapper::filterAxes(bool force) { diff --git a/services/input/InputReader.h b/services/input/InputReader.h index 0485617..62ac4b2 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -540,7 +540,7 @@ private: sp<PointerControllerInterface> mPointerController; struct LockedState { - uint32_t buttonState; + int32_t buttonState; nsecs_t downTime; } mLocked; @@ -602,6 +602,7 @@ protected: int32_t toolMajor; int32_t toolMinor; int32_t orientation; + bool isStylus; inline bool operator== (const PointerData& other) const { return id == other.id @@ -625,7 +626,7 @@ protected: PointerData pointers[MAX_POINTERS]; BitSet32 idBits; uint32_t idToIndex[MAX_POINTER_ID + 1]; - uint32_t buttonState; + int32_t buttonState; void copyFrom(const TouchData& other) { pointerCount = other.pointerCount; @@ -774,9 +775,11 @@ protected: // Current and previous touch sample data. TouchData mCurrentTouch; + PointerProperties mCurrentTouchProperties[MAX_POINTERS]; PointerCoords mCurrentTouchCoords[MAX_POINTERS]; TouchData mLastTouch; + PointerProperties mLastTouchProperties[MAX_POINTERS]; PointerCoords mLastTouchCoords[MAX_POINTERS]; // The time the primary pointer last went down. @@ -987,11 +990,13 @@ private: Mode currentGestureMode; BitSet32 currentGestureIdBits; uint32_t currentGestureIdToIndex[MAX_POINTER_ID + 1]; + PointerProperties currentGestureProperties[MAX_POINTERS]; PointerCoords currentGestureCoords[MAX_POINTERS]; Mode lastGestureMode; BitSet32 lastGestureIdBits; uint32_t lastGestureIdToIndex[MAX_POINTER_ID + 1]; + PointerProperties lastGestureProperties[MAX_POINTERS]; PointerCoords lastGestureCoords[MAX_POINTERS]; // Pointer coords and ids for the current spots. @@ -1068,17 +1073,22 @@ private: // method will take care of setting the index and transmuting the action to DOWN or UP // it is the first / last pointer to go down / up. void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, - int32_t action, int32_t flags, uint32_t metaState, int32_t edgeFlags, - const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits, + int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, + int32_t edgeFlags, + const PointerProperties* properties, const PointerCoords* coords, + const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime); - // Updates pointer coords for pointers with specified ids that have moved. + // Updates pointer coords and properties for pointers with specified ids that have moved. // Returns true if any of them changed. - bool updateMovedPointerCoords(const PointerCoords* inCoords, const uint32_t* inIdToIndex, - PointerCoords* outCoords, const uint32_t* outIdToIndex, BitSet32 idBits) const; + bool updateMovedPointers(const PointerProperties* inProperties, + const PointerCoords* inCoords, const uint32_t* inIdToIndex, + PointerProperties* outProperties, PointerCoords* outCoords, + const uint32_t* outIdToIndex, BitSet32 idBits) const; void suppressSwipeOntoVirtualKeys(nsecs_t when); + int32_t getTouchToolType(bool isStylus) const; bool isPointInsideSurfaceLocked(int32_t x, int32_t y); const VirtualKey* findVirtualKeyHitLocked(int32_t x, int32_t y); @@ -1134,7 +1144,7 @@ private: int32_t mY; int32_t mPressure; int32_t mToolWidth; - uint32_t mButtonState; + int32_t mButtonState; void initialize(); @@ -1198,7 +1208,7 @@ private: } } mAccumulator; - uint32_t mButtonState; + int32_t mButtonState; void initialize(); diff --git a/services/input/PointerController.cpp b/services/input/PointerController.cpp index ffef720..b87c98d 100644 --- a/services/input/PointerController.cpp +++ b/services/input/PointerController.cpp @@ -137,7 +137,7 @@ void PointerController::move(float deltaX, float deltaY) { setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY); } -void PointerController::setButtonState(uint32_t buttonState) { +void PointerController::setButtonState(int32_t buttonState) { #if DEBUG_POINTER_UPDATES LOGD("Set button state 0x%08x", buttonState); #endif @@ -148,7 +148,7 @@ void PointerController::setButtonState(uint32_t buttonState) { } } -uint32_t PointerController::getButtonState() const { +int32_t PointerController::getButtonState() const { AutoMutex _l(mLock); return mLocked.buttonState; diff --git a/services/input/PointerController.h b/services/input/PointerController.h index b9184ac..c7435ee 100644 --- a/services/input/PointerController.h +++ b/services/input/PointerController.h @@ -53,10 +53,10 @@ public: virtual void move(float deltaX, float deltaY) = 0; /* Sets a mask that indicates which buttons are pressed. */ - virtual void setButtonState(uint32_t buttonState) = 0; + virtual void setButtonState(int32_t buttonState) = 0; /* Gets a mask that indicates which buttons are pressed. */ - virtual uint32_t getButtonState() const = 0; + virtual int32_t getButtonState() const = 0; /* Sets the absolute location of the pointer. */ virtual void setPosition(float x, float y) = 0; @@ -183,8 +183,8 @@ public: virtual bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const; virtual void move(float deltaX, float deltaY); - virtual void setButtonState(uint32_t buttonState); - virtual uint32_t getButtonState() const; + virtual void setButtonState(int32_t buttonState); + virtual int32_t getButtonState() const; virtual void setPosition(float x, float y); virtual void getPosition(float* outX, float* outY) const; virtual void fade(); @@ -258,7 +258,7 @@ private: SpriteIcon pointerIcon; bool pointerIconChanged; - uint32_t buttonState; + int32_t buttonState; Vector<Spot*> spots; Vector<sp<Sprite> > recycledSprites; diff --git a/services/input/tests/InputDispatcher_test.cpp b/services/input/tests/InputDispatcher_test.cpp index 3650da0..3db3473 100644 --- a/services/input/tests/InputDispatcher_test.cpp +++ b/services/input/tests/InputDispatcher_test.cpp @@ -142,17 +142,19 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) { TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { MotionEvent event; - int32_t pointerIds[MAX_POINTERS + 1]; + PointerProperties pointerProperties[MAX_POINTERS + 1]; PointerCoords pointerCoords[MAX_POINTERS + 1]; for (int i = 0; i <= MAX_POINTERS; i++) { - pointerIds[i] = i; + pointerProperties[i].clear(); + pointerProperties[i].id = i; + pointerCoords[i].clear(); } // Rejects undefined motion actions. event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - /*action*/ -1, 0, 0, AMETA_NONE, 0, 0, 0, 0, + /*action*/ -1, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerIds, pointerCoords); + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with undefined action."; @@ -160,18 +162,18 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects pointer down with invalid index. event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, AMETA_NONE, 0, 0, 0, 0, + 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerIds, pointerCoords); + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer down index too large."; event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_POINTER_DOWN | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, AMETA_NONE, 0, 0, 0, 0, + 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerIds, pointerCoords); + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer down index too small."; @@ -179,65 +181,65 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects pointer up with invalid index. event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, AMETA_NONE, 0, 0, 0, 0, + 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerIds, pointerCoords); + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer up index too large."; event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_POINTER_UP | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, AMETA_NONE, 0, 0, 0, 0, + 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerIds, pointerCoords); + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer up index too small."; // Rejects motion events with invalid number of pointers. event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, + AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 0, pointerIds, pointerCoords); + /*pointerCount*/ 0, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with 0 pointers."; event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, + AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ MAX_POINTERS + 1, pointerIds, pointerCoords); + /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with more than MAX_POINTERS pointers."; // Rejects motion events with invalid pointer ids. - pointerIds[0] = -1; + pointerProperties[0].id = -1; event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, + AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerIds, pointerCoords); + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer ids less than 0."; - pointerIds[0] = MAX_POINTER_ID + 1; + pointerProperties[0].id = MAX_POINTER_ID + 1; event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, + AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerIds, pointerCoords); + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer ids greater than MAX_POINTER_ID."; // Rejects motion events with duplicate pointer ids. - pointerIds[0] = 1; - pointerIds[1] = 1; + pointerProperties[0].id = 1; + pointerProperties[1].id = 1; event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, + AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 2, pointerIds, pointerCoords); + /*pointerCount*/ 2, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with duplicate pointer ids."; diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp index 54bb9d7..f5d7ae8 100644 --- a/services/input/tests/InputReader_test.cpp +++ b/services/input/tests/InputReader_test.cpp @@ -77,10 +77,10 @@ private: virtual void move(float deltaX, float deltaY) { } - virtual void setButtonState(uint32_t buttonState) { + virtual void setButtonState(int32_t buttonState) { } - virtual uint32_t getButtonState() const { + virtual int32_t getButtonState() const { return 0; } @@ -236,9 +236,10 @@ public: int32_t action; int32_t flags; int32_t metaState; + int32_t buttonState; int32_t edgeFlags; uint32_t pointerCount; - Vector<int32_t> pointerIds; + Vector<PointerProperties> pointerProperties; Vector<PointerCoords> pointerCoords; float xPrecision; float yPrecision; @@ -337,8 +338,9 @@ private: virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, - int32_t metaState, int32_t edgeFlags, - uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords, + int32_t metaState, int32_t buttonState, int32_t edgeFlags, + uint32_t pointerCount, const PointerProperties* pointerProperties, + const PointerCoords* pointerCoords, float xPrecision, float yPrecision, nsecs_t downTime) { NotifyMotionArgs args; args.eventTime = eventTime; @@ -348,10 +350,11 @@ private: args.action = action; args.flags = flags; args.metaState = metaState; + args.buttonState = buttonState; args.edgeFlags = edgeFlags; args.pointerCount = pointerCount; - args.pointerIds.clear(); - args.pointerIds.appendArray(pointerIds, pointerCount); + args.pointerProperties.clear(); + args.pointerProperties.appendArray(pointerProperties, pointerCount); args.pointerCoords.clear(); args.pointerCoords.appendArray(pointerCoords, pointerCount); args.xPrecision = xPrecision; @@ -2104,9 +2107,11 @@ TEST_F(CursorInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaStat ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); ASSERT_EQ(0, args.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); + ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, args.buttonState); ASSERT_EQ(0, args.edgeFlags); ASSERT_EQ(uint32_t(1), args.pointerCount); - ASSERT_EQ(0, args.pointerIds[0]); + ASSERT_EQ(0, args.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, args.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.xPrecision); @@ -2123,9 +2128,11 @@ TEST_F(CursorInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaStat ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); ASSERT_EQ(0, args.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); + ASSERT_EQ(0, args.buttonState); ASSERT_EQ(0, args.edgeFlags); ASSERT_EQ(uint32_t(1), args.pointerCount); - ASSERT_EQ(0, args.pointerIds[0]); + ASSERT_EQ(0, args.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, args.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.xPrecision); @@ -2756,9 +2763,11 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfB ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_EQ(0, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -2778,9 +2787,11 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfB ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_EQ(0, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -2799,9 +2810,11 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfB ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_EQ(0, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -2847,9 +2860,11 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMoves ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_EQ(0, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -2868,9 +2883,11 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMoves ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_EQ(0, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -2908,9 +2925,11 @@ TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) { ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_EQ(0, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -2931,9 +2950,11 @@ TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) { ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_EQ(0, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -2952,9 +2973,11 @@ TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) { ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_EQ(0, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -3215,9 +3238,11 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_EQ(0, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -3233,10 +3258,13 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); - ASSERT_EQ(1, motionArgs.pointerIds[1]); + ASSERT_EQ(0, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(1, motionArgs.pointerProperties[1].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -3261,10 +3289,13 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); - ASSERT_EQ(1, motionArgs.pointerIds[1]); + ASSERT_EQ(0, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(1, motionArgs.pointerProperties[1].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -3288,10 +3319,13 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); - ASSERT_EQ(1, motionArgs.pointerIds[1]); + ASSERT_EQ(0, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(1, motionArgs.pointerProperties[1].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -3308,9 +3342,11 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(1, motionArgs.pointerIds[0]); + ASSERT_EQ(1, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -3331,9 +3367,11 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(1, motionArgs.pointerIds[0]); + ASSERT_EQ(1, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -3357,10 +3395,13 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); - ASSERT_EQ(1, motionArgs.pointerIds[1]); + ASSERT_EQ(0, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(1, motionArgs.pointerProperties[1].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -3384,10 +3425,13 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); - ASSERT_EQ(1, motionArgs.pointerIds[1]); + ASSERT_EQ(0, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(1, motionArgs.pointerProperties[1].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -3404,9 +3448,11 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_EQ(0, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -3425,9 +3471,11 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); + ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(0, motionArgs.pointerIds[0]); + ASSERT_EQ(0, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -3464,7 +3512,8 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(1, motionArgs.pointerIds[0]); + ASSERT_EQ(1, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); @@ -3472,8 +3521,10 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(1, motionArgs.pointerIds[0]); - ASSERT_EQ(2, motionArgs.pointerIds[1]); + ASSERT_EQ(1, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(2, motionArgs.pointerProperties[1].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -3492,8 +3543,10 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(1, motionArgs.pointerIds[0]); - ASSERT_EQ(2, motionArgs.pointerIds[1]); + ASSERT_EQ(1, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(2, motionArgs.pointerProperties[1].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -3510,8 +3563,10 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(1, motionArgs.pointerIds[0]); - ASSERT_EQ(2, motionArgs.pointerIds[1]); + ASSERT_EQ(1, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(2, motionArgs.pointerProperties[1].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -3520,7 +3575,8 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(2, motionArgs.pointerIds[0]); + ASSERT_EQ(2, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); @@ -3534,7 +3590,8 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(2, motionArgs.pointerIds[0]); + ASSERT_EQ(2, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); @@ -3552,8 +3609,10 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(2, motionArgs.pointerIds[0]); - ASSERT_EQ(3, motionArgs.pointerIds[1]); + ASSERT_EQ(2, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(3, motionArgs.pointerProperties[1].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -3570,8 +3629,10 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); - ASSERT_EQ(2, motionArgs.pointerIds[0]); - ASSERT_EQ(3, motionArgs.pointerIds[1]); + ASSERT_EQ(2, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(3, motionArgs.pointerProperties[1].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -3580,7 +3641,8 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(3, motionArgs.pointerIds[0]); + ASSERT_EQ(3, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0)); @@ -3591,7 +3653,8 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); - ASSERT_EQ(3, motionArgs.pointerIds[0]); + ASSERT_EQ(3, motionArgs.pointerProperties[0].id); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0)); @@ -3641,7 +3704,7 @@ TEST_F(MultiTouchInputMapperTest, Process_AllAxes_WithDefaultCalibration) { FakeInputDispatcher::NotifyMotionArgs args; ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(id, args.pointerIds[0]); + ASSERT_EQ(id, args.pointerProperties[0].id); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], x, y, pressure, size, touchMajor, touchMinor, toolMajor, toolMinor, orientation)); } diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java index 4ba6060..fb97089 100644 --- a/services/java/com/android/server/accessibility/TouchExplorer.java +++ b/services/java/com/android/server/accessibility/TouchExplorer.java @@ -31,6 +31,7 @@ import android.view.MotionEvent; import android.view.ViewConfiguration; import android.view.WindowManagerPolicy; import android.view.MotionEvent.PointerCoords; +import android.view.MotionEvent.PointerProperties; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; @@ -112,8 +113,13 @@ public class TouchExplorer implements Explorer { // Temporary array for mapping new to old pointer IDs while filtering inactive pointers. private final int [] mTempNewToOldPointerIndexMap = new int[MAX_POINTER_COUNT]; + // Temporary array for storing PointerProperties + private final PointerProperties[] mTempPointerProperties = + PointerProperties.createArray(MAX_POINTER_COUNT); + // Temporary array for storing PointerCoords - private final PointerCoords[] mTempPointerCoords= new PointerCoords[MAX_POINTER_COUNT]; + private final PointerCoords[] mTempPointerCoords = + PointerCoords.createArray(MAX_POINTER_COUNT); // The maximal distance between two pointers so they are // considered to be performing a drag operation. @@ -172,11 +178,6 @@ public class TouchExplorer implements Explorer { mHandler = new Handler(context.getMainLooper()); mSendHoverDelayed = new SendHoverDelayed(); mAccessibilityManager = AccessibilityManager.getInstance(context); - - // Populate the temporary array with PointerCorrds to be reused. - for (int i = 0, count = mTempPointerCoords.length; i < count; i++) { - mTempPointerCoords[i] = new PointerCoords(); - } } public void clear(MotionEvent event, int policyFlags) { @@ -574,9 +575,9 @@ public class TouchExplorer implements Explorer { * @param policyFlags The policy flags associated with the event. */ private void sendDownForAllActiveNotInjectedPointers(MotionEvent prototype, int policyFlags) { - PointerCoords[] pointerCoords = mTempPointerCoords; - PointerTracker pointerTracker = mPointerTracker; - int[] pointerIds = mTempPointerIds; + final PointerProperties[] pointerProperties = mTempPointerProperties; + final PointerCoords[] pointerCoords = mTempPointerCoords; + final PointerTracker pointerTracker = mPointerTracker; int pointerDataIndex = 0; final int pinterCount = prototype.getPointerCount(); @@ -593,7 +594,7 @@ public class TouchExplorer implements Explorer { } // Populate and inject an event for the current pointer. - pointerIds[pointerDataIndex] = pointerId; + prototype.getPointerProperties(i, pointerProperties[pointerDataIndex]); prototype.getPointerCoords(i, pointerCoords[pointerDataIndex]); final long downTime = pointerTracker.getLastInjectedDownEventTime(); @@ -602,7 +603,8 @@ public class TouchExplorer implements Explorer { final long pointerDownTime = SystemClock.uptimeMillis(); MotionEvent event = MotionEvent.obtain(downTime, pointerDownTime, - action, pointerCount, pointerIds, pointerCoords, prototype.getMetaState(), + action, pointerCount, pointerProperties, pointerCoords, + prototype.getMetaState(), prototype.getButtonState(), prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(), prototype.getEdgeFlags(), prototype.getSource(), prototype.getFlags()); sendMotionEvent(event, policyFlags); @@ -620,9 +622,9 @@ public class TouchExplorer implements Explorer { * @param policyFlags The policy flags associated with the event. */ private void sendUpForInjectedDownPointers(MotionEvent prototype, int policyFlags) { - PointerTracker pointerTracker = mPointerTracker; - PointerCoords[] pointerCoords = mTempPointerCoords; - int[] pointerIds = mTempPointerIds; + final PointerTracker pointerTracker = mPointerTracker; + final PointerProperties[] pointerProperties = mTempPointerProperties; + final PointerCoords[] pointerCoords = mTempPointerCoords; int pointerDataIndex = 0; final int pointerCount = prototype.getPointerCount(); @@ -635,7 +637,7 @@ public class TouchExplorer implements Explorer { } // Populate and inject event. - pointerIds[pointerDataIndex] = pointerId; + prototype.getPointerProperties(i, pointerProperties[pointerDataIndex]); prototype.getPointerCoords(i, pointerCoords[pointerDataIndex]); final long downTime = pointerTracker.getLastInjectedDownEventTime(); @@ -644,7 +646,8 @@ public class TouchExplorer implements Explorer { final long eventTime = SystemClock.uptimeMillis(); MotionEvent event = MotionEvent.obtain(downTime, eventTime, action, - newPointerCount, pointerIds, pointerCoords, prototype.getMetaState(), + newPointerCount, pointerProperties, pointerCoords, + prototype.getMetaState(), prototype.getButtonState(), prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(), prototype.getEdgeFlags(), prototype.getSource(), prototype.getFlags()); @@ -678,8 +681,8 @@ public class TouchExplorer implements Explorer { } // Filter out inactive pointers from the event and inject it. - PointerCoords[] pointerCoords = mTempPointerCoords; - int[] pointerIds = mTempPointerIds; + final PointerProperties[] pointerProperties = mTempPointerProperties; + final PointerCoords[] pointerCoords = mTempPointerCoords; int [] newToOldPointerIndexMap = mTempNewToOldPointerIndexMap; int newPointerIndex = 0; int actionIndex = prototype.getActionIndex(); @@ -698,7 +701,7 @@ public class TouchExplorer implements Explorer { } newToOldPointerIndexMap[newPointerIndex] = oldPointerIndex; - pointerIds[newPointerIndex] = pointerId; + prototype.getPointerProperties(oldPointerIndex, pointerProperties[newPointerIndex]); prototype.getPointerCoords(oldPointerIndex, pointerCoords[newPointerIndex]); newPointerIndex++; @@ -714,7 +717,8 @@ public class TouchExplorer implements Explorer { final int action = computeInjectionAction(prototype.getActionMasked(), actionIndex); final int newPointerCount = newPointerIndex; MotionEvent prunedEvent = MotionEvent.obtain(downTime, prototype.getEventTime(), action, - newPointerCount, pointerIds, pointerCoords, prototype.getMetaState(), + newPointerCount, pointerProperties, pointerCoords, + prototype.getMetaState(), prototype.getButtonState(), prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(), prototype.getEdgeFlags(), prototype.getSource(),prototype.getFlags()); @@ -743,18 +747,19 @@ public class TouchExplorer implements Explorer { * @param policyFlags The policy flags associated with the event. */ private void sendDragEvent(MotionEvent prototype, int action, int policyFlags) { - PointerCoords[] pointerCoords = mTempPointerCoords; - int[] pointerIds = mTempPointerIds; + final PointerProperties[] pointerProperties = mTempPointerProperties; + final PointerCoords[] pointerCoords = mTempPointerCoords; final int pointerId = mDraggingPointerId; final int pointerIndex = prototype.findPointerIndex(pointerId); // Populate the event with the date of the dragging pointer and inject it. - pointerIds[0] = pointerId; + prototype.getPointerProperties(pointerIndex, pointerProperties[0]); prototype.getPointerCoords(pointerIndex, pointerCoords[0]); MotionEvent event = MotionEvent.obtain(prototype.getDownTime(), - prototype.getEventTime(), action, 1, pointerIds, pointerCoords, - prototype.getMetaState(), prototype.getXPrecision(), prototype.getYPrecision(), + prototype.getEventTime(), action, 1, pointerProperties, pointerCoords, + prototype.getMetaState(), prototype.getButtonState(), + prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(), prototype.getEdgeFlags(), prototype.getSource(), prototype.getFlags()); @@ -769,32 +774,27 @@ public class TouchExplorer implements Explorer { * @param policyFlags The policy flags associated with the event. */ private void sendActionDownAndUp(MotionEvent prototype, int policyFlags) { - PointerCoords[] pointerCoords = mTempPointerCoords; - int[] pointerIds = mTempPointerIds; + final PointerProperties[] pointerProperties = mTempPointerProperties; + final PointerCoords[] pointerCoords = mTempPointerCoords; final int pointerId = mPointerTracker.getLastReceivedUpPointerId(); final int pointerIndex = prototype.findPointerIndex(pointerId); // Send down. - pointerIds[0] = pointerId; + prototype.getPointerProperties(pointerIndex, pointerProperties[0]); prototype.getPointerCoords(pointerIndex, pointerCoords[0]); final long downTime = SystemClock.uptimeMillis(); - - MotionEvent downEvent = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN, - 1, mTempPointerIds, mTempPointerCoords, prototype.getMetaState(), + MotionEvent event = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN, + 1, pointerProperties, pointerCoords, + prototype.getMetaState(), prototype.getButtonState(), prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(), prototype.getEdgeFlags(), prototype.getSource(), prototype.getFlags()); - - // Clone the down event before recycling it. - MotionEvent upEvent = MotionEvent.obtain(downEvent); - - sendMotionEvent(downEvent, policyFlags); - downEvent.recycle(); + sendMotionEvent(event, policyFlags); // Send up. - upEvent.setAction(MotionEvent.ACTION_UP); - sendMotionEvent(upEvent, policyFlags); - upEvent.recycle(); + event.setAction(MotionEvent.ACTION_UP); + sendMotionEvent(event, policyFlags); + event.recycle(); } /** @@ -807,21 +807,20 @@ public class TouchExplorer implements Explorer { */ private void sendHoverEvent(MotionEvent prototype, int action, int pointerIndex, int policyFlags) { - PointerCoords[] pointerCoords = mTempPointerCoords; - int[] pointerIds = mTempPointerIds; + final PointerProperties[] pointerProperties = mTempPointerProperties; + final PointerCoords[] pointerCoords = mTempPointerCoords; - // Keep only data relevant to a hover event. - pointerIds[0] = prototype.getPointerId(pointerIndex); - pointerCoords[0].clear(); - pointerCoords[0].x = prototype.getX(pointerIndex); - pointerCoords[0].y = prototype.getY(pointerIndex); + prototype.getPointerProperties(pointerIndex, pointerProperties[0]); + prototype.getPointerCoords(pointerIndex, pointerCoords[0]); final long downTime = mPointerTracker.getLastInjectedDownEventTime(); // Populate and inject a hover event. MotionEvent hoverEvent = MotionEvent.obtain(downTime, prototype.getEventTime(), action, - 1, pointerIds, pointerCoords, 0, 0, 0, prototype.getDeviceId(), 0, - prototype.getSource(), 0); + 1, pointerProperties, pointerCoords, + prototype.getMetaState(), prototype.getButtonState(), + prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(), + prototype.getEdgeFlags(), prototype.getSource(), prototype.getFlags()); sendMotionEvent(hoverEvent, policyFlags); hoverEvent.recycle(); |