summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.xml11
-rw-r--r--core/java/android/view/MotionEvent.java72
-rw-r--r--core/java/android/view/ViewGroup.java16
-rw-r--r--core/java/com/android/internal/widget/PointerLocationView.java33
-rw-r--r--core/jni/android_view_MotionEvent.cpp4
-rw-r--r--libs/ui/InputTransport.cpp3
-rw-r--r--native/include/android/input.h8
-rwxr-xr-xpolicy/src/com/android/internal/policy/impl/PhoneWindowManager.java5
-rw-r--r--services/input/EventHub.cpp42
-rw-r--r--services/input/EventHub.h5
-rw-r--r--services/input/InputDispatcher.cpp165
-rw-r--r--services/input/InputDispatcher.h24
-rw-r--r--services/input/InputReader.cpp43
-rw-r--r--services/input/tests/InputReader_test.cpp4
14 files changed, 231 insertions, 204 deletions
diff --git a/api/current.xml b/api/current.xml
index 019ca71..480ad93 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -217741,6 +217741,17 @@
visibility="public"
>
</field>
+<field name="ACTION_HOVER_MOVE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_MASK"
type="int"
transient="false"
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index a1326d2..cc37a28 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -157,7 +157,15 @@ public final class MotionEvent extends InputEvent implements Parcelable {
* {@link #ACTION_POINTER_ID_MASK} indicate which pointer changed.
*/
public static final int ACTION_POINTER_UP = 6;
-
+
+ /**
+ * Constant for {@link #getAction}: 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.
+ */
+ public static final int ACTION_HOVER_MOVE = 7;
+
/**
* Bits in the action code that represent a pointer index, used with
* {@link #ACTION_POINTER_DOWN} and {@link #ACTION_POINTER_UP}. Shifting
@@ -269,9 +277,8 @@ public final class MotionEvent extends InputEvent implements Parcelable {
* <li>For a touch screen, reports the absolute X screen position of the center of
* the touch contact area. The units are display pixels.
* <li>For a touch pad, reports the absolute X surface position of the center of the touch
- * contact area. The units are device-specific because the touch pad is not necessarily
- * associated with a display. Use {@link InputDevice#getMotionRange(int)} to query
- * the effective range of values.
+ * contact area. The units are device-dependent; use {@link InputDevice#getMotionRange(int)}
+ * to query the effective range of values.
* <li>For a mouse, reports the absolute X screen position of the mouse pointer.
* The units are display pixels.
* <li>For a trackball, reports the relative horizontal displacement of the trackball.
@@ -317,7 +324,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
* Constant used to identify the Pressure axis of a motion event.
* <p>
* <ul>
- * <li>For a touch screen or touch pad, reports the approximate pressure applied to the device
+ * <li>For a touch screen or touch pad, reports the approximate pressure applied to the surface
* by a finger or other tool. The value is normalized to a range from
* 0 (no pressure at all) to 1 (normal pressure), although values higher than 1
* may be generated depending on the calibration of the input device.
@@ -342,7 +349,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
* <li>For a touch screen or touch pad, reports the approximate size of the contact area in
* relation to the maximum detectable size for the device. The value is normalized
* to a range from 0 (smallest detectable size) to 1 (largest detectable size),
- * although it is not a linear scale. This value is of very limited use.
+ * although it is not a linear scale. This value is of limited use.
* To obtain calibrated size information, use
* {@link #AXIS_TOUCH_MAJOR} or {@link #AXIS_TOOL_MAJOR}.
* </ul>
@@ -475,7 +482,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
* Constant used to identify the Vertical Scroll axis of a motion event.
* <p>
* <ul>
- * <li>For a mouse, reports the relative movement of vertical scroll wheel.
+ * <li>For a mouse, reports the relative movement of the vertical scroll wheel.
* The value is normalized to a range from -1.0 (up) to 1.0 (down).
* </ul>
* </p><p>
@@ -493,7 +500,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
* Constant used to identify the Horizontal Scroll axis of a motion event.
* <p>
* <ul>
- * <li>For a mouse, reports the relative movement of horizontal scroll wheel.
+ * <li>For a mouse, reports the relative movement of the horizontal scroll wheel.
* The value is normalized to a range from -1.0 (left) to 1.0 (right).
* </ul>
* </p><p>
@@ -969,9 +976,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
* 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 -- one of either
- * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or
- * {@link #ACTION_CANCEL}.
+ * @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.
@@ -1010,9 +1015,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
* 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 -- one of either
- * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or
- * {@link #ACTION_CANCEL}.
+ * @param action The kind of action being performed, such as {@link #ACTION_DOWN}.
* @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
@@ -1062,9 +1065,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
* 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 -- one of either
- * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or
- * {@link #ACTION_CANCEL}.
+ * @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 x The X coordinate of this event.
* @param y The Y coordinate of this event.
@@ -1106,9 +1107,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
* 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 -- one of either
- * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or
- * {@link #ACTION_CANCEL}.
+ * @param action The kind of action being performed, such as {@link #ACTION_DOWN}.
* @param x The X coordinate of this event.
* @param y The Y coordinate of this event.
* @param metaState The state of any meta / modifier keys that were in effect when
@@ -1203,23 +1202,20 @@ public final class MotionEvent extends InputEvent implements Parcelable {
}
/**
- * Return the kind of action being performed -- one of either
- * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or
- * {@link #ACTION_CANCEL}. Consider using {@link #getActionMasked}
- * and {@link #getActionIndex} to retrieve the separate masked action
- * and pointer index.
+ * Return the kind of action being performed.
+ * Consider using {@link #getActionMasked} and {@link #getActionIndex} to retrieve
+ * the separate masked action and pointer index.
+ * @return The action, such as {@link #ACTION_DOWN} or
+ * the combination of {@link #ACTION_POINTER_DOWN} with a shifted pointer index.
*/
public final int getAction() {
return nativeGetAction(mNativePtr);
}
/**
- * Return the masked action being performed, without pointer index
- * information. May be any of the actions: {@link #ACTION_DOWN},
- * {@link #ACTION_MOVE}, {@link #ACTION_UP}, {@link #ACTION_CANCEL},
- * {@link #ACTION_POINTER_DOWN}, or {@link #ACTION_POINTER_UP}.
- * Use {@link #getActionIndex} to return the index associated with
- * pointer actions.
+ * Return the masked action being performed, without pointer index information.
+ * Use {@link #getActionIndex} to return the index associated with pointer actions.
+ * @return The action, such as {@link #ACTION_DOWN} or {@link #ACTION_POINTER_DOWN}.
*/
public final int getActionMasked() {
return nativeGetAction(mNativePtr) & ACTION_MASK;
@@ -1228,10 +1224,12 @@ public final class MotionEvent extends InputEvent implements Parcelable {
/**
* For {@link #ACTION_POINTER_DOWN} or {@link #ACTION_POINTER_UP}
* as returned by {@link #getActionMasked}, this returns the associated
- * pointer index. The index may be used with {@link #getPointerId(int)},
+ * pointer index.
+ * The index may be used with {@link #getPointerId(int)},
* {@link #getX(int)}, {@link #getY(int)}, {@link #getPressure(int)},
* and {@link #getSize(int)} to get information about the pointer that has
* gone down or up.
+ * @return The index associated with the action.
*/
public final int getActionIndex() {
return (nativeGetAction(mNativePtr) & ACTION_POINTER_INDEX_MASK)
@@ -2096,7 +2094,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
* current location, position and size is updated to the new values.
* The current values in the event are added to a list of historical values.
*
- * Only applies to {@link #ACTION_MOVE} events.
+ * Only applies to {@link #ACTION_MOVE} or {@link #ACTION_HOVER_MOVE} events.
*
* @param eventTime The time stamp (in ms) for this data.
* @param x The new X position.
@@ -2123,7 +2121,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
* current location, position and size is updated to the new values.
* The current values in the event are added to a list of historical values.
*
- * Only applies to {@link #ACTION_MOVE} events.
+ * Only applies to {@link #ACTION_MOVE} or {@link #ACTION_HOVER_MOVE} events.
*
* @param eventTime The time stamp (in ms) for this data.
* @param pointerCoords The new pointer coordinates.
@@ -2178,6 +2176,8 @@ public final class MotionEvent extends InputEvent implements Parcelable {
return "ACTION_CANCEL";
case ACTION_MOVE:
return "ACTION_MOVE";
+ case ACTION_HOVER_MOVE:
+ return "ACTION_HOVER_MOVE";
}
int index = (action & ACTION_POINTER_INDEX_MASK) >> ACTION_POINTER_INDEX_SHIFT;
switch (action & ACTION_MASK) {
@@ -2203,8 +2203,8 @@ public final class MotionEvent extends InputEvent implements Parcelable {
}
/**
- * Gets an axis by its symbolic name such as "KEYCODE_A" or an
- * equivalent numeric constant such as "1001".
+ * Gets an axis by its symbolic name such as "AXIS_X" or an
+ * equivalent numeric constant such as "42".
*
* @param symbolicName The symbolic name of the axis.
* @return The axis or -1 if not found.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index b5a2558..a0d4263 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1166,7 +1166,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final int actionMasked = action & MotionEvent.ACTION_MASK;
// Handle an initial down.
- if (actionMasked == MotionEvent.ACTION_DOWN) {
+ if (actionMasked == MotionEvent.ACTION_DOWN
+ || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
// Throw away all previous state when starting a new touch gesture.
// The framework may have dropped the up or cancel event for the previous gesture
// due to an app switch, ANR, or some other state change.
@@ -1176,7 +1177,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
// Check for interception.
final boolean intercepted;
- if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
+ if (actionMasked == MotionEvent.ACTION_DOWN
+ || actionMasked == MotionEvent.ACTION_HOVER_MOVE
+ || mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev);
@@ -1198,7 +1201,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
boolean alreadyDispatchedToNewTouchTarget = false;
if (!canceled && !intercepted) {
if (actionMasked == MotionEvent.ACTION_DOWN
- || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)) {
+ || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
+ || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
final int actionIndex = ev.getActionIndex(); // always 0 for down
final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
: TouchTarget.ALL_POINTER_IDS;
@@ -1299,7 +1303,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
// Update list of touch targets for pointer up or cancel, if needed.
- if (canceled || actionMasked == MotionEvent.ACTION_UP) {
+ if (canceled
+ || actionMasked == MotionEvent.ACTION_UP
+ || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
resetTouchState();
} else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
final int actionIndex = ev.getActionIndex();
@@ -1542,6 +1548,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final int newAction;
if (cancel) {
newAction = MotionEvent.ACTION_CANCEL;
+ } else if (oldAction == MotionEvent.ACTION_HOVER_MOVE) {
+ newAction = MotionEvent.ACTION_HOVER_MOVE;
} else {
final int oldMaskedAction = oldAction & MotionEvent.ACTION_MASK;
if (oldMaskedAction == MotionEvent.ACTION_POINTER_DOWN
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 4a6857c..c72d0e8 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -27,6 +27,7 @@ import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
+import android.view.MotionEvent.PointerCoords;
import java.util.ArrayList;
@@ -43,7 +44,7 @@ public class PointerLocationView extends View {
private boolean mCurDown;
// Most recent coordinates.
- private MotionEvent.PointerCoords mCoords = new MotionEvent.PointerCoords();
+ private PointerCoords mCoords = new PointerCoords();
// Most recent velocity.
private float mXVelocity;
@@ -86,6 +87,7 @@ public class PointerLocationView extends View {
private int mMaxNumPointers;
private int mActivePointerId;
private final ArrayList<PointerState> mPointers = new ArrayList<PointerState>();
+ private final PointerCoords mHoverCoords = new PointerCoords();
private final VelocityTracker mVelocity;
@@ -386,9 +388,11 @@ public class PointerLocationView extends View {
}
final int NI = event.getPointerCount();
-
+
+ final boolean hover = (action == MotionEvent.ACTION_HOVER_MOVE);
mCurDown = action != MotionEvent.ACTION_UP
- && action != MotionEvent.ACTION_CANCEL;
+ && action != MotionEvent.ACTION_CANCEL
+ && !hover;
mCurNumPointers = mCurDown ? NI : 0;
if (mMaxNumPointers < mCurNumPointers) {
mMaxNumPointers = mCurNumPointers;
@@ -399,22 +403,27 @@ public class PointerLocationView extends View {
for (int i=0; i<NI; i++) {
final int id = event.getPointerId(i);
- final PointerState ps = mPointers.get(id);
+ final PointerState ps = hover ? null : mPointers.get(id);
+ final PointerCoords coords = ps != null ? ps.mCoords : mHoverCoords;
final int N = event.getHistorySize();
for (int j=0; j<N; j++) {
- event.getHistoricalPointerCoords(i, j, ps.mCoords);
+ event.getHistoricalPointerCoords(i, j, coords);
if (mPrintCoords) {
- logPointerCoords(ps.mCoords, id);
+ logPointerCoords(coords, id);
+ }
+ if (ps != null) {
+ ps.addTrace(event.getHistoricalX(i, j), event.getHistoricalY(i, j));
}
- ps.addTrace(event.getHistoricalX(i, j), event.getHistoricalY(i, j));
}
- event.getPointerCoords(i, ps.mCoords);
+ event.getPointerCoords(i, coords);
if (mPrintCoords) {
- logPointerCoords(ps.mCoords, id);
+ logPointerCoords(coords, id);
+ }
+ if (ps != null) {
+ ps.addTrace(coords.x, coords.y);
+ ps.mXVelocity = mVelocity.getXVelocity(id);
+ ps.mYVelocity = mVelocity.getYVelocity(id);
}
- ps.addTrace(ps.mCoords.x, ps.mCoords.y);
- ps.mXVelocity = mVelocity.getXVelocity(id);
- ps.mYVelocity = mVelocity.getYVelocity(id);
}
if (action == MotionEvent.ACTION_UP
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 5ba1cff..b014006 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -217,7 +217,7 @@ static void pointerCoordsToNative(JNIEnv* env, jobject pointerCoordsObj,
uint32_t index = 0;
do {
- uint32_t axis = __builtin_ctz(bits);
+ uint32_t axis = __builtin_ctzll(bits);
uint64_t axisBit = 1LL << axis;
bits &= ~axisBit;
outRawPointerCoords->setAxisValue(axis, values[index++]);
@@ -298,7 +298,7 @@ static void pointerCoordsFromNative(JNIEnv* env, const PointerCoords* rawPointer
const float* values = rawPointerCoords->values;
uint32_t index = 0;
do {
- uint32_t axis = __builtin_ctz(remainingBits);
+ uint32_t axis = __builtin_ctzll(remainingBits);
uint64_t axisBit = 1LL << axis;
remainingBits &= ~axisBit;
outBits |= axisBit;
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index 83d9556..5c57a76 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -412,7 +412,8 @@ status_t InputPublisher::publishMotionEvent(
// Cache essential information about the motion event to ensure that a malicious consumer
// cannot confuse the publisher by modifying the contents of the shared memory buffer while
// it is being updated.
- if (action == AMOTION_EVENT_ACTION_MOVE) {
+ if (action == AMOTION_EVENT_ACTION_MOVE
+ || action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
mMotionEventPointerCount = pointerCount;
mMotionEventSampleDataStride = InputMessage::sampleDataStride(pointerCount);
mMotionEventSampleDataTail = InputMessage::sampleDataPtrIncrement(
diff --git a/native/include/android/input.h b/native/include/android/input.h
index d531489..d516037 100644
--- a/native/include/android/input.h
+++ b/native/include/android/input.h
@@ -281,7 +281,13 @@ enum {
/* A non-primary pointer has gone up.
* The bits in AMOTION_EVENT_ACTION_POINTER_INDEX_MASK indicate which pointer changed.
*/
- AMOTION_EVENT_ACTION_POINTER_UP = 6
+ AMOTION_EVENT_ACTION_POINTER_UP = 6,
+
+ /* A change happened but the pointer is not down (unlike AMOTION_EVENT_ACTION_MOVE).
+ * The motion contains the most recent point, as well as any intermediate points since
+ * the last hover move event.
+ */
+ AMOTION_EVENT_ACTION_HOVER_MOVE = 7,
};
/*
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index c921425..156391e 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -1490,10 +1490,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
FallbackAction outFallbackAction) {
// Consult the key character map for specific fallback actions.
// For example, map NUMPAD_1 to MOVE_HOME when NUMLOCK is not pressed.
- if (kcm.getFallbackAction(keyCode, metaState, outFallbackAction)) {
- return true;
- }
- return false;
+ return kcm.getFallbackAction(keyCode, metaState, outFallbackAction);
}
/**
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index f79d106..b31381a 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -101,12 +101,14 @@ EventHub::Device::Device(int fd, int32_t id, const String8& path,
const InputDeviceIdentifier& identifier) :
next(NULL),
fd(fd), id(id), path(path), identifier(identifier),
- classes(0), keyBitmask(NULL), configuration(NULL), virtualKeyMap(NULL) {
+ classes(0), keyBitmask(NULL), relBitmask(NULL),
+ configuration(NULL), virtualKeyMap(NULL) {
}
EventHub::Device::~Device() {
close();
delete[] keyBitmask;
+ delete[] relBitmask;
delete configuration;
delete virtualKeyMap;
}
@@ -189,6 +191,18 @@ status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis,
return OK;
}
+bool EventHub::hasRelativeAxis(int32_t deviceId, int axis) const {
+ if (axis >= 0 && axis <= REL_MAX) {
+ AutoMutex _l(mLock);
+
+ Device* device = getDeviceLocked(deviceId);
+ if (device && device->relBitmask) {
+ return test_bit(axis, device->relBitmask);
+ }
+ }
+ return false;
+}
+
int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const {
if (scanCode >= 0 && scanCode <= KEY_MAX) {
AutoMutex _l(mLock);
@@ -772,6 +786,24 @@ int EventHub::openDevice(const char *devicePath) {
memset(sw_bitmask, 0, sizeof(sw_bitmask));
ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask);
+ device->keyBitmask = new uint8_t[sizeof(key_bitmask)];
+ if (device->keyBitmask != NULL) {
+ memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
+ } else {
+ delete device;
+ LOGE("out of memory allocating key bitmask");
+ return -1;
+ }
+
+ device->relBitmask = new uint8_t[sizeof(rel_bitmask)];
+ if (device->relBitmask != NULL) {
+ memcpy(device->relBitmask, rel_bitmask, sizeof(rel_bitmask));
+ } else {
+ delete device;
+ LOGE("out of memory allocating rel bitmask");
+ return -1;
+ }
+
// See if this is a keyboard. Ignore everything in the button range except for
// joystick and gamepad buttons which are handled like keyboards for the most part.
bool haveKeyboardKeys = containsNonZeroByte(key_bitmask, 0, sizeof_bit_array(BTN_MISC))
@@ -781,14 +813,6 @@ int EventHub::openDevice(const char *devicePath) {
sizeof_bit_array(BTN_DIGI));
if (haveKeyboardKeys || haveGamepadButtons) {
device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
- device->keyBitmask = new uint8_t[sizeof(key_bitmask)];
- if (device->keyBitmask != NULL) {
- memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
- } else {
- delete device;
- LOGE("out of memory allocating key bitmask");
- return -1;
- }
}
// See if this is a cursor device such as a trackball or mouse.
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index 35712f5..23bb344 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -167,6 +167,8 @@ public:
virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
RawAbsoluteAxisInfo* outAxisInfo) const = 0;
+ virtual bool hasRelativeAxis(int32_t deviceId, int axis) const = 0;
+
virtual status_t mapKey(int32_t deviceId, int scancode,
int32_t* outKeycode, uint32_t* outFlags) const = 0;
@@ -224,6 +226,8 @@ public:
virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
RawAbsoluteAxisInfo* outAxisInfo) const;
+ virtual bool hasRelativeAxis(int32_t deviceId, int axis) const;
+
virtual status_t mapKey(int32_t deviceId, int scancode,
int32_t* outKeycode, uint32_t* outFlags) const;
@@ -272,6 +276,7 @@ private:
uint32_t classes;
uint8_t* keyBitmask;
+ uint8_t* relBitmask;
String8 configurationFile;
PropertyMap* configuration;
VirtualKeyMap* virtualKeyMap;
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index ae11fb1..ef984d4 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -115,6 +115,7 @@ static bool isValidMotionAction(int32_t action, size_t pointerCount) {
case AMOTION_EVENT_ACTION_CANCEL:
case AMOTION_EVENT_ACTION_MOVE:
case AMOTION_EVENT_ACTION_OUTSIDE:
+ case AMOTION_EVENT_ACTION_HOVER_MOVE:
return true;
case AMOTION_EVENT_ACTION_POINTER_DOWN:
case AMOTION_EVENT_ACTION_POINTER_UP: {
@@ -318,7 +319,8 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout,
uint32_t source = motionEntry->source;
if (! isAppSwitchDue
&& motionEntry->next == & mInboundQueue.tailSentinel // exactly one event
- && motionEntry->action == AMOTION_EVENT_ACTION_MOVE
+ && (motionEntry->action == AMOTION_EVENT_ACTION_MOVE
+ || motionEntry->action == AMOTION_EVENT_ACTION_HOVER_MOVE)
&& deviceId == mThrottleState.lastDeviceId
&& source == mThrottleState.lastSource) {
nsecs_t nextTime = mThrottleState.lastEventTime
@@ -478,7 +480,8 @@ bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
// If the application takes too long to catch up then we drop all events preceding
// the touch into the other window.
MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
- if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN
+ if ((motionEntry->action == AMOTION_EVENT_ACTION_DOWN
+ || motionEntry->action == AMOTION_EVENT_ACTION_HOVER_MOVE)
&& (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
&& mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY
&& mInputTargetWaitApplication != NULL) {
@@ -838,12 +841,13 @@ bool InputDispatcher::dispatchMotionLocked(
bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
// Identify targets.
+ bool conflictingPointerActions = false;
if (! mCurrentInputTargetsValid) {
int32_t injectionResult;
if (isPointerEvent) {
// Pointer event. (eg. touchscreen)
injectionResult = findTouchedWindowTargetsLocked(currentTime,
- entry, nextWakeupTime);
+ entry, nextWakeupTime, &conflictingPointerActions);
} else {
// Non touch event. (eg. trackball)
injectionResult = findFocusedWindowTargetsLocked(currentTime,
@@ -863,6 +867,10 @@ bool InputDispatcher::dispatchMotionLocked(
}
// Dispatch the motion.
+ if (conflictingPointerActions) {
+ synthesizeCancelationEventsForAllConnectionsLocked(
+ InputState::CANCEL_POINTER_EVENTS, "Conflicting pointer actions.");
+ }
dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
return true;
}
@@ -1123,7 +1131,7 @@ Unresponsive:
}
int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
- const MotionEntry* entry, nsecs_t* nextWakeupTime) {
+ const MotionEntry* entry, nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) {
enum InjectionPermission {
INJECTION_PERMISSION_UNKNOWN,
INJECTION_PERMISSION_GRANTED,
@@ -1166,31 +1174,38 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
// Update the touch state as needed based on the properties of the touch event.
int32_t injectionResult = INPUT_EVENT_INJECTION_PENDING;
InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN;
- bool isSplit, wrongDevice;
- if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
- mTempTouchState.reset();
- mTempTouchState.down = true;
- mTempTouchState.deviceId = entry->deviceId;
- mTempTouchState.source = entry->source;
- isSplit = false;
- wrongDevice = false;
+
+ bool isSplit = mTouchState.split;
+ bool wrongDevice = mTouchState.down
+ && (mTouchState.deviceId != entry->deviceId
+ || mTouchState.source != entry->source);
+ if (maskedAction == AMOTION_EVENT_ACTION_DOWN
+ || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {
+ bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN;
+ if (wrongDevice && !down) {
+ mTempTouchState.copyFrom(mTouchState);
+ } else {
+ mTempTouchState.reset();
+ mTempTouchState.down = down;
+ mTempTouchState.deviceId = entry->deviceId;
+ mTempTouchState.source = entry->source;
+ isSplit = false;
+ wrongDevice = false;
+ }
} else {
mTempTouchState.copyFrom(mTouchState);
- isSplit = mTempTouchState.split;
- wrongDevice = mTempTouchState.down
- && (mTempTouchState.deviceId != entry->deviceId
- || mTempTouchState.source != entry->source);
- if (wrongDevice) {
+ }
+ if (wrongDevice) {
#if DEBUG_INPUT_DISPATCHER_POLICY
- LOGD("Dropping event because a pointer for a different device is already down.");
+ LOGD("Dropping event because a pointer for a different device is already down.");
#endif
- injectionResult = INPUT_EVENT_INJECTION_FAILED;
- goto Failed;
- }
+ injectionResult = INPUT_EVENT_INJECTION_FAILED;
+ goto Failed;
}
if (maskedAction == AMOTION_EVENT_ACTION_DOWN
- || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
+ || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)
+ || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {
/* Case 1: New splittable pointer going down. */
int32_t pointerIndex = getMotionEventActionPointerIndex(action);
@@ -1365,7 +1380,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
// If this is the first pointer going down and the touched window has a wallpaper
// then also add the touched wallpaper windows so they are locked in for the duration
// of the touch gesture.
- if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
+ if (maskedAction == AMOTION_EVENT_ACTION_DOWN
+ || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {
const InputWindow* foregroundWindow = mTempTouchState.getFirstForegroundWindow();
if (foregroundWindow->hasWallpaper) {
for (size_t i = 0; i < mWindows.size(); i++) {
@@ -1404,12 +1420,14 @@ Failed:
if (injectionPermission == INJECTION_PERMISSION_GRANTED) {
if (!wrongDevice) {
if (maskedAction == AMOTION_EVENT_ACTION_UP
- || maskedAction == AMOTION_EVENT_ACTION_CANCEL) {
+ || maskedAction == AMOTION_EVENT_ACTION_CANCEL
+ || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {
// All pointers up or canceled.
mTempTouchState.reset();
} else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
// First pointer went down.
if (mTouchState.down) {
+ *outConflictingPointerActions = true;
#if DEBUG_FOCUS
LOGD("Pointer down received while already down.");
#endif
@@ -1750,29 +1768,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
// Update the connection's input state.
EventEntry* eventEntry = dispatchEntry->eventEntry;
- InputState::Consistency consistency = connection->inputState.trackEvent(eventEntry);
-
-#if FILTER_INPUT_EVENTS
- // Filter out inconsistent sequences of input events.
- // The input system may drop or inject events in a way that could violate implicit
- // invariants on input state and potentially cause an application to crash
- // or think that a key or pointer is stuck down. Technically we make no guarantees
- // of consistency but it would be nice to improve on this where possible.
- // XXX: This code is a proof of concept only. Not ready for prime time.
- if (consistency == InputState::TOLERABLE) {
-#if DEBUG_DISPATCH_CYCLE
- LOGD("channel '%s' ~ Sending an event that is inconsistent with the connection's "
- "current input state but that is likely to be tolerated by the application.",
- connection->getInputChannelName());
-#endif
- } else if (consistency == InputState::BROKEN) {
- LOGI("channel '%s' ~ Dropping an event that is inconsistent with the connection's "
- "current input state and that is likely to cause the application to crash.",
- connection->getInputChannelName());
- startNextDispatchCycleLocked(currentTime, connection);
- return;
- }
-#endif
+ connection->inputState.trackEvent(eventEntry);
// Publish the event.
status_t status;
@@ -2307,7 +2303,8 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t
AutoMutex _l(mLock);
// Attempt batching and streaming of move events.
- if (action == AMOTION_EVENT_ACTION_MOVE) {
+ if (action == AMOTION_EVENT_ACTION_MOVE
+ || action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
// BATCHING CASE
//
// Try to append a move sample to the tail of the inbound queue for this device.
@@ -2326,7 +2323,7 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t
continue;
}
- if (motionEntry->action != AMOTION_EVENT_ACTION_MOVE
+ if (motionEntry->action != action
|| motionEntry->source != source
|| motionEntry->pointerCount != pointerCount
|| motionEntry->isInjected()) {
@@ -2385,7 +2382,7 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t
MotionEntry* motionEntry = static_cast<MotionEntry*>(
dispatchEntry->eventEntry);
- if (motionEntry->action != AMOTION_EVENT_ACTION_MOVE
+ if (motionEntry->action != action
|| motionEntry->deviceId != deviceId
|| motionEntry->source != source
|| motionEntry->pointerCount != pointerCount
@@ -3529,21 +3526,20 @@ bool InputDispatcher::InputState::isNeutral() const {
return mKeyMementos.isEmpty() && mMotionMementos.isEmpty();
}
-InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackEvent(
+void InputDispatcher::InputState::trackEvent(
const EventEntry* entry) {
switch (entry->type) {
case EventEntry::TYPE_KEY:
- return trackKey(static_cast<const KeyEntry*>(entry));
+ trackKey(static_cast<const KeyEntry*>(entry));
+ break;
case EventEntry::TYPE_MOTION:
- return trackMotion(static_cast<const MotionEntry*>(entry));
-
- default:
- return CONSISTENT;
+ trackMotion(static_cast<const MotionEntry*>(entry));
+ break;
}
}
-InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackKey(
+void InputDispatcher::InputState::trackKey(
const KeyEntry* entry) {
int32_t action = entry->action;
for (size_t i = 0; i < mKeyMementos.size(); i++) {
@@ -3555,19 +3551,20 @@ InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackKey(
switch (action) {
case AKEY_EVENT_ACTION_UP:
mKeyMementos.removeAt(i);
- return CONSISTENT;
+ return;
case AKEY_EVENT_ACTION_DOWN:
- return TOLERABLE;
+ mKeyMementos.removeAt(i);
+ goto Found;
default:
- return BROKEN;
+ return;
}
}
}
- switch (action) {
- case AKEY_EVENT_ACTION_DOWN: {
+Found:
+ if (action == AKEY_EVENT_ACTION_DOWN) {
mKeyMementos.push();
KeyMemento& memento = mKeyMementos.editTop();
memento.deviceId = entry->deviceId;
@@ -3576,15 +3573,10 @@ InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackKey(
memento.scanCode = entry->scanCode;
memento.flags = entry->flags;
memento.downTime = entry->downTime;
- return CONSISTENT;
- }
-
- default:
- return BROKEN;
}
}
-InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackMotion(
+void InputDispatcher::InputState::trackMotion(
const MotionEntry* entry) {
int32_t action = entry->action & AMOTION_EVENT_ACTION_MASK;
for (size_t i = 0; i < mMotionMementos.size(); i++) {
@@ -3594,40 +3586,28 @@ InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackMotio
switch (action) {
case AMOTION_EVENT_ACTION_UP:
case AMOTION_EVENT_ACTION_CANCEL:
+ case AMOTION_EVENT_ACTION_HOVER_MOVE:
mMotionMementos.removeAt(i);
- return CONSISTENT;
+ return;
case AMOTION_EVENT_ACTION_DOWN:
- return TOLERABLE;
-
- case AMOTION_EVENT_ACTION_POINTER_DOWN:
- if (entry->pointerCount == memento.pointerCount + 1) {
- memento.setPointers(entry);
- return CONSISTENT;
- }
- return BROKEN;
+ mMotionMementos.removeAt(i);
+ goto Found;
case AMOTION_EVENT_ACTION_POINTER_UP:
- if (entry->pointerCount == memento.pointerCount - 1) {
- memento.setPointers(entry);
- return CONSISTENT;
- }
- return BROKEN;
-
+ case AMOTION_EVENT_ACTION_POINTER_DOWN:
case AMOTION_EVENT_ACTION_MOVE:
- if (entry->pointerCount == memento.pointerCount) {
- return CONSISTENT;
- }
- return BROKEN;
+ memento.setPointers(entry);
+ return;
default:
- return BROKEN;
+ return;
}
}
}
- switch (action) {
- case AMOTION_EVENT_ACTION_DOWN: {
+Found:
+ if (action == AMOTION_EVENT_ACTION_DOWN) {
mMotionMementos.push();
MotionMemento& memento = mMotionMementos.editTop();
memento.deviceId = entry->deviceId;
@@ -3636,11 +3616,6 @@ InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackMotio
memento.yPrecision = entry->yPrecision;
memento.downTime = entry->downTime;
memento.setPointers(entry);
- return CONSISTENT;
- }
-
- default:
- return BROKEN;
}
}
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index 006c6b8..7abe014 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -593,19 +593,6 @@ private:
* synthesized when events are dropped. */
class InputState {
public:
- // Specifies whether a given event will violate input state consistency.
- enum Consistency {
- // The event is consistent with the current input state.
- CONSISTENT,
- // The event is inconsistent with the current input state but applications
- // will tolerate it. eg. Down followed by another down.
- TOLERABLE,
- // The event is inconsistent with the current input state and will probably
- // cause applications to crash. eg. Up without prior down, move with
- // unexpected number of pointers.
- BROKEN
- };
-
// Specifies the sources to cancel.
enum CancelationOptions {
CANCEL_ALL_EVENTS = 0,
@@ -621,16 +608,13 @@ private:
bool isNeutral() const;
// Records tracking information for an event that has just been published.
- // Returns whether the event is consistent with the current input state.
- Consistency trackEvent(const EventEntry* entry);
+ void trackEvent(const EventEntry* entry);
// Records tracking information for a key event that has just been published.
- // Returns whether the event is consistent with the current input state.
- Consistency trackKey(const KeyEntry* entry);
+ void trackKey(const KeyEntry* entry);
// Records tracking information for a motion event that has just been published.
- // Returns whether the event is consistent with the current input state.
- Consistency trackMotion(const MotionEntry* entry);
+ void trackMotion(const MotionEntry* entry);
// Synthesizes cancelation events for the current state and resets the tracked state.
void synthesizeCancelationEvents(nsecs_t currentTime, Allocator* allocator,
@@ -911,7 +895,7 @@ private:
int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry,
nsecs_t* nextWakeupTime);
int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry,
- nsecs_t* nextWakeupTime);
+ nsecs_t* nextWakeupTime, bool* outConflictingPointerActions);
void addWindowTargetLocked(const InputWindow* window, int32_t targetFlags,
BitSet32 pointerIds);
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 47cfa05..a963c72 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -565,15 +565,6 @@ InputDevice::~InputDevice() {
mMappers.clear();
}
-static void dumpMotionRange(String8& dump, const InputDeviceInfo& deviceInfo,
- int32_t rangeType, const char* name) {
- const InputDeviceInfo::MotionRange* range = deviceInfo.getMotionRange(rangeType);
- if (range) {
- dump.appendFormat(INDENT3 "%s: min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f\n",
- name, range->min, range->max, range->flat, range->fuzz);
- }
-}
-
void InputDevice::dump(String8& dump) {
InputDeviceInfo deviceInfo;
getDeviceInfo(& deviceInfo);
@@ -582,17 +573,24 @@ void InputDevice::dump(String8& dump) {
deviceInfo.getName().string());
dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
- if (!deviceInfo.getMotionRanges().isEmpty()) {
+
+ const KeyedVector<int32_t, InputDeviceInfo::MotionRange> ranges = deviceInfo.getMotionRanges();
+ if (!ranges.isEmpty()) {
dump.append(INDENT2 "Motion Ranges:\n");
- dumpMotionRange(dump, deviceInfo, AMOTION_EVENT_AXIS_X, "X");
- dumpMotionRange(dump, deviceInfo, AMOTION_EVENT_AXIS_Y, "Y");
- dumpMotionRange(dump, deviceInfo, AMOTION_EVENT_AXIS_PRESSURE, "Pressure");
- dumpMotionRange(dump, deviceInfo, AMOTION_EVENT_AXIS_SIZE, "Size");
- dumpMotionRange(dump, deviceInfo, AMOTION_EVENT_AXIS_TOUCH_MAJOR, "TouchMajor");
- dumpMotionRange(dump, deviceInfo, AMOTION_EVENT_AXIS_TOUCH_MINOR, "TouchMinor");
- dumpMotionRange(dump, deviceInfo, AMOTION_EVENT_AXIS_TOOL_MAJOR, "ToolMajor");
- dumpMotionRange(dump, deviceInfo, AMOTION_EVENT_AXIS_TOOL_MINOR, "ToolMinor");
- dumpMotionRange(dump, deviceInfo, AMOTION_EVENT_AXIS_ORIENTATION, "Orientation");
+ for (size_t i = 0; i < ranges.size(); i++) {
+ int32_t axis = ranges.keyAt(i);
+ const char* label = getAxisLabel(axis);
+ char name[32];
+ if (label) {
+ strncpy(name, label, sizeof(name));
+ name[sizeof(name) - 1] = '\0';
+ } else {
+ snprintf(name, sizeof(name), "%d", axis);
+ }
+ const InputDeviceInfo::MotionRange& range = ranges.valueAt(i);
+ dump.appendFormat(INDENT3 "%s: min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f\n",
+ name, range.min, range.max, range.flat, range.fuzz);
+ }
}
size_t numMappers = mMappers.size();
@@ -1123,6 +1121,9 @@ void CursorInputMapper::configure() {
mVWheelScale = 1.0f;
mHWheelScale = 1.0f;
+
+ mHaveVWheel = getEventHub()->hasRelativeAxis(getDeviceId(), REL_WHEEL);
+ mHaveHWheel = getEventHub()->hasRelativeAxis(getDeviceId(), REL_HWHEEL);
}
void CursorInputMapper::configureParameters() {
@@ -1274,8 +1275,10 @@ void CursorInputMapper::sync(nsecs_t when) {
if (downChanged) {
motionEventAction = mLocked.down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
- } else {
+ } else if (mLocked.down || mPointerController == NULL) {
motionEventAction = AMOTION_EVENT_ACTION_MOVE;
+ } else {
+ motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE;
}
if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 648250e..fac71bb 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -561,6 +561,10 @@ private:
return -1;
}
+ virtual bool hasRelativeAxis(int32_t deviceId, int axis) const {
+ return false;
+ }
+
virtual status_t mapKey(int32_t deviceId, int scancode,
int32_t* outKeycode, uint32_t* outFlags) const {
Device* device = getDevice(deviceId);