diff options
Diffstat (limited to 'services')
-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 |
6 files changed, 139 insertions, 144 deletions
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); |