diff options
-rw-r--r-- | api/current.xml | 11 | ||||
-rw-r--r-- | core/java/android/view/MotionEvent.java | 72 | ||||
-rw-r--r-- | core/java/android/view/ViewGroup.java | 16 | ||||
-rw-r--r-- | core/java/com/android/internal/widget/PointerLocationView.java | 33 | ||||
-rw-r--r-- | core/jni/android_view_MotionEvent.cpp | 4 | ||||
-rw-r--r-- | libs/ui/InputTransport.cpp | 3 | ||||
-rw-r--r-- | native/include/android/input.h | 8 | ||||
-rwxr-xr-x | policy/src/com/android/internal/policy/impl/PhoneWindowManager.java | 5 | ||||
-rw-r--r-- | services/input/EventHub.cpp | 42 | ||||
-rw-r--r-- | services/input/EventHub.h | 5 | ||||
-rw-r--r-- | services/input/InputDispatcher.cpp | 165 | ||||
-rw-r--r-- | services/input/InputDispatcher.h | 24 | ||||
-rw-r--r-- | services/input/InputReader.cpp | 43 | ||||
-rw-r--r-- | services/input/tests/InputReader_test.cpp | 4 |
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); |