From 842500e146cdc0036b2a1a3e2acc7626d005128b Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Fri, 13 Mar 2015 17:32:02 -0700 Subject: Fuse stylus and touch screen data. TODO: Ensure we dispatch new pressure and button data when stylus is stationary. Change-Id: I10a665a9b81ff4b9acd01bf72f0fc2e0c2abc203 --- services/inputflinger/EventHub.cpp | 17 + services/inputflinger/EventHub.h | 3 + services/inputflinger/InputReader.cpp | 972 +++++++++++++++-------- services/inputflinger/InputReader.h | 182 ++++- services/inputflinger/tests/InputReader_test.cpp | 8 + 5 files changed, 823 insertions(+), 359 deletions(-) (limited to 'services/inputflinger') diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp index 4d54d56..6b60c7c 100644 --- a/services/inputflinger/EventHub.cpp +++ b/services/inputflinger/EventHub.cpp @@ -131,6 +131,13 @@ uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses) { } } + // External stylus gets the pressure axis + if (deviceClasses & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { + if (axis == ABS_PRESSURE) { + return INPUT_DEVICE_CLASS_EXTERNAL_STYLUS; + } + } + // Joystick devices get the rest. return deviceClasses & INPUT_DEVICE_CLASS_JOYSTICK; } @@ -1185,6 +1192,16 @@ status_t EventHub::openDeviceLocked(const char *devicePath) { && test_bit(ABS_X, device->absBitmask) && test_bit(ABS_Y, device->absBitmask)) { device->classes |= INPUT_DEVICE_CLASS_TOUCH; + // Is this a BT stylus? + } else if ((test_bit(ABS_PRESSURE, device->absBitmask) || + test_bit(BTN_TOUCH, device->keyBitmask)) + && !test_bit(ABS_X, device->absBitmask) + && !test_bit(ABS_Y, device->absBitmask)) { + device->classes |= INPUT_DEVICE_CLASS_EXTERNAL_STYLUS; + // Keyboard will try to claim some of the buttons but we really want to reserve those so we + // can fuse it with the touch screen data, so just take them back. Note this means an + // external stylus cannot also be a keyboard device. + device->classes &= ~INPUT_DEVICE_CLASS_KEYBOARD; } // See if this device is a joystick. diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h index d08f60e..3ec4910 100644 --- a/services/inputflinger/EventHub.h +++ b/services/inputflinger/EventHub.h @@ -134,6 +134,9 @@ enum { /* The input device has a microphone. */ INPUT_DEVICE_CLASS_MIC = 0x00000400, + /* The input device is an external stylus (has data we want to fuse with touch data). */ + INPUT_DEVICE_CLASS_EXTERNAL_STYLUS = 0x00000800, + /* The input device is virtual (not a real device, not part of UI configuration). */ INPUT_DEVICE_CLASS_VIRTUAL = 0x40000000, diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp index b39f367..5654799 100644 --- a/services/inputflinger/InputReader.cpp +++ b/services/inputflinger/InputReader.cpp @@ -39,12 +39,16 @@ // Log debug messages about the vibrator. #define DEBUG_VIBRATOR 0 +// Log debug messages about fusing stylus data. +#define DEBUG_STYLUS_FUSION 0 + #include "InputReader.h" #include #include #include +#include #include #include #include @@ -65,6 +69,10 @@ namespace android { // Maximum number of slots supported when using the slot-based Multitouch Protocol B. static const size_t MAX_SLOTS = 32; +// Maximum amount of latency to add to touch events while waiting for data from an +// external stylus. +static const nsecs_t EXTERNAL_STYLUS_DATA_TIMEOUT = ms2ns(32); + // --- Static Functions --- template @@ -381,6 +389,10 @@ void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { mDevices.add(deviceId, device); bumpGenerationLocked(); + + if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { + notifyExternalStylusPresenceChanged(); + } } void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { @@ -403,6 +415,10 @@ void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { device->getId(), device->getName().string(), device->getSources()); } + if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { + notifyExternalStylusPresenceChanged(); + } + device->reset(when); delete device; } @@ -469,6 +485,11 @@ InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controlle device->addMapper(new JoystickInputMapper(device)); } + // External stylus-like devices. + if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { + device->addMapper(new ExternalStylusInputMapper(device)); + } + return device; } @@ -539,6 +560,27 @@ int32_t InputReader::getGlobalMetaStateLocked() { return mGlobalMetaState; } +void InputReader::notifyExternalStylusPresenceChanged() { + refreshConfigurationLocked(InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE); +} + +void InputReader::getExternalStylusDevicesLocked(Vector& outDevices) { + for (size_t i = 0; i < mDevices.size(); i++) { + InputDevice* device = mDevices.valueAt(i); + if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS && !device->isIgnored()) { + outDevices.push(); + device->getDeviceInfo(&outDevices.editTop()); + } + } +} + +void InputReader::dispatchExternalStylusState(const StylusState& state) { + for (size_t i = 0; i < mDevices.size(); i++) { + InputDevice* device = mDevices.valueAt(i); + device->updateExternalStylusState(state); + } +} + void InputReader::disableVirtualKeysUntilLocked(nsecs_t time) { mDisableVirtualKeysTimeout = time; } @@ -829,6 +871,15 @@ int32_t InputReader::ContextImpl::bumpGeneration() { return mReader->bumpGenerationLocked(); } +void InputReader::ContextImpl::getExternalStylusDevices(Vector& outDevices) { + // lock is already held by whatever called refreshConfigurationLocked + mReader->getExternalStylusDevicesLocked(outDevices); +} + +void InputReader::ContextImpl::dispatchExternalStylusState(const StylusState& state) { + mReader->dispatchExternalStylusState(state); +} + InputReaderPolicyInterface* InputReader::ContextImpl::getPolicy() { return mReader->mPolicy.get(); } @@ -1012,6 +1063,14 @@ void InputDevice::timeoutExpired(nsecs_t when) { } } +void InputDevice::updateExternalStylusState(const StylusState& state) { + size_t numMappers = mMappers.size(); + for (size_t i = 0; i < numMappers; i++) { + InputMapper* mapper = mMappers[i]; + mapper->updateExternalStylusState(state); + } +} + void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) { outDeviceInfo->initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias, mIsExternal, mHasMic); @@ -1290,7 +1349,9 @@ void TouchButtonAccumulator::configure(InputDevice* device) { void TouchButtonAccumulator::reset(InputDevice* device) { mBtnTouch = device->isKeyPressed(BTN_TOUCH); mBtnStylus = device->isKeyPressed(BTN_STYLUS); - mBtnStylus2 = device->isKeyPressed(BTN_STYLUS); + // BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch + mBtnStylus2 = + device->isKeyPressed(BTN_STYLUS2) || device->isKeyPressed(BTN_0); mBtnToolFinger = device->isKeyPressed(BTN_TOOL_FINGER); mBtnToolPen = device->isKeyPressed(BTN_TOOL_PEN); mBtnToolRubber = device->isKeyPressed(BTN_TOOL_RUBBER); @@ -1331,6 +1392,7 @@ void TouchButtonAccumulator::process(const RawEvent* rawEvent) { mBtnStylus = rawEvent->value; break; case BTN_STYLUS2: + case BTN_0:// BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch mBtnStylus2 = rawEvent->value; break; case BTN_TOOL_FINGER: @@ -1806,6 +1868,10 @@ int32_t InputMapper::getMetaState() { return 0; } +void InputMapper::updateExternalStylusState(const StylusState& state) { + +} + void InputMapper::fadePointer() { } @@ -1827,6 +1893,12 @@ void InputMapper::dumpRawAbsoluteAxisInfo(String8& dump, } } +void InputMapper::dumpStylusState(String8& dump, const StylusState& state) { + dump.appendFormat(INDENT4 "When: %" PRId64 "\n", state.when); + dump.appendFormat(INDENT4 "Pressure: %f\n", state.pressure); + dump.appendFormat(INDENT4 "Button State: 0x%08x\n", state.buttons); + dump.appendFormat(INDENT4 "Tool Type: %" PRId32 "\n", state.toolType); +} // --- SwitchInputMapper --- @@ -2708,12 +2780,12 @@ void TouchInputMapper::dump(String8& dump) { dump.appendFormat(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter); dump.appendFormat(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale); - dump.appendFormat(INDENT3 "Last Button State: 0x%08x\n", mLastButtonState); + dump.appendFormat(INDENT3 "Last Button State: 0x%08x\n", mLastRawState.buttonState); dump.appendFormat(INDENT3 "Last Raw Touch: pointerCount=%d\n", - mLastRawPointerData.pointerCount); - for (uint32_t i = 0; i < mLastRawPointerData.pointerCount; i++) { - const RawPointerData::Pointer& pointer = mLastRawPointerData.pointers[i]; + mLastRawState.rawPointerData.pointerCount); + for (uint32_t i = 0; i < mLastRawState.rawPointerData.pointerCount; i++) { + const RawPointerData::Pointer& pointer = mLastRawState.rawPointerData.pointers[i]; dump.appendFormat(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, " "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, " "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, " @@ -2726,10 +2798,11 @@ void TouchInputMapper::dump(String8& dump) { } dump.appendFormat(INDENT3 "Last Cooked Touch: pointerCount=%d\n", - mLastCookedPointerData.pointerCount); - for (uint32_t i = 0; i < mLastCookedPointerData.pointerCount; i++) { - const PointerProperties& pointerProperties = mLastCookedPointerData.pointerProperties[i]; - const PointerCoords& pointerCoords = mLastCookedPointerData.pointerCoords[i]; + mLastCookedState.cookedPointerData.pointerCount); + for (uint32_t i = 0; i < mLastCookedState.cookedPointerData.pointerCount; i++) { + const PointerProperties& pointerProperties = + mLastCookedState.cookedPointerData.pointerProperties[i]; + const PointerCoords& pointerCoords = mLastCookedState.cookedPointerData.pointerCoords[i]; dump.appendFormat(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, " "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, toolMinor=%0.3f, " "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, " @@ -2746,9 +2819,18 @@ void TouchInputMapper::dump(String8& dump) { pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TILT), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), pointerProperties.toolType, - toString(mLastCookedPointerData.isHovering(i))); + toString(mLastCookedState.cookedPointerData.isHovering(i))); } + dump.append(INDENT3 "Stylus Fusion:\n"); + dump.appendFormat(INDENT4 "ExternalStylusConnected: %s\n", + toString(mExternalStylusConnected)); + dump.appendFormat(INDENT4 "External Stylus ID: %" PRId64 "\n", mExternalStylusId); + dump.appendFormat(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n", + mExternalStylusDataTimeout); + dump.append(INDENT3 "External Stylus State:\n"); + dumpStylusState(dump, mExternalStylusState); + if (mDeviceMode == DEVICE_MODE_POINTER) { dump.appendFormat(INDENT3 "Pointer Gesture Detector:\n"); dump.appendFormat(INDENT4 "XMovementScale: %0.3f\n", @@ -2786,7 +2868,7 @@ void TouchInputMapper::configure(nsecs_t when, resolveCalibration(); } - if (!changes || (changes & InputReaderConfiguration::TOUCH_AFFINE_TRANSFORMATION)) { + if (!changes || (changes & InputReaderConfiguration::CHANGE_TOUCH_AFFINE_TRANSFORMATION)) { // Update location calibration to reflect current settings updateAffineTransformation(); } @@ -2801,7 +2883,8 @@ void TouchInputMapper::configure(nsecs_t when, bool resetNeeded = false; if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO | InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT - | InputReaderConfiguration::CHANGE_SHOW_TOUCHES))) { + | InputReaderConfiguration::CHANGE_SHOW_TOUCHES + | InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) { // Configure device sources, surface dimensions, orientation and // scaling factors. configureSurface(when, &resetNeeded); @@ -2814,6 +2897,16 @@ void TouchInputMapper::configure(nsecs_t when, } } +void TouchInputMapper::resolveExternalStylusPresence() { + Vector devices; + mContext->getExternalStylusDevices(devices); + mExternalStylusConnected = !devices.isEmpty(); + + if (!mExternalStylusConnected) { + resetExternalStylus(); + } +} + void TouchInputMapper::configureParameters() { // Use the pointer presentation mode for devices that do not support distinct // multitouch. The spot-based presentation relies on being able to accurately @@ -2950,9 +3043,15 @@ void TouchInputMapper::dumpRawPointerAxes(String8& dump) { dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.slot, "Slot"); } +bool TouchInputMapper::hasExternalStylus() const { + return mExternalStylusConnected; +} + void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { int32_t oldDeviceMode = mDeviceMode; + resolveExternalStylusPresence(); + // Determine device mode. if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER && mConfig.pointerGesturesEnabled) { @@ -2965,7 +3064,7 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { && mParameters.hasAssociatedDisplay) { mSource = AINPUT_SOURCE_TOUCHSCREEN; mDeviceMode = DEVICE_MODE_DIRECT; - if (hasStylus()) { + if (hasStylus() || hasExternalStylus()) { mSource |= AINPUT_SOURCE_STYLUS; } } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_NAVIGATION) { @@ -3710,28 +3809,21 @@ void TouchInputMapper::reset(nsecs_t when) { mWheelXVelocityControl.reset(); mWheelYVelocityControl.reset(); - mCurrentRawPointerData.clear(); - mLastRawPointerData.clear(); - mCurrentCookedPointerData.clear(); - mLastCookedPointerData.clear(); - mCurrentButtonState = 0; - mLastButtonState = 0; - mCurrentRawVScroll = 0; - mCurrentRawHScroll = 0; - mCurrentFingerIdBits.clear(); - mLastFingerIdBits.clear(); - mCurrentStylusIdBits.clear(); - mLastStylusIdBits.clear(); - mCurrentMouseIdBits.clear(); - mLastMouseIdBits.clear(); + mRawStatesPending.clear(); + mCurrentRawState.clear(); + mCurrentCookedState.clear(); + mLastRawState.clear(); + mLastCookedState.clear(); mPointerUsage = POINTER_USAGE_NONE; mSentHoverEnter = false; + mHavePointerIds = false; mDownTime = 0; mCurrentVirtualKey.down = false; mPointerGesture.reset(); mPointerSimple.reset(); + resetExternalStylus(); if (mPointerController != NULL) { mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); @@ -3741,6 +3833,13 @@ void TouchInputMapper::reset(nsecs_t when) { InputMapper::reset(when); } +void TouchInputMapper::resetExternalStylus() { + mExternalStylusState.clear(); + mExternalStylusId = -1; + mExternalStylusDataTimeout = LLONG_MAX; + mExternalStylusDataPending = false; +} + void TouchInputMapper::process(const RawEvent* rawEvent) { mCursorButtonAccumulator.process(rawEvent); mCursorScrollAccumulator.process(rawEvent); @@ -3752,155 +3851,264 @@ void TouchInputMapper::process(const RawEvent* rawEvent) { } void TouchInputMapper::sync(nsecs_t when) { + const RawState* last = mRawStatesPending.isEmpty() ? + &mCurrentRawState : &mRawStatesPending.top(); + + // Push a new state. + mRawStatesPending.push(); + RawState* next = &mRawStatesPending.editTop(); + next->clear(); + next->when = when; + // Sync button state. - mCurrentButtonState = mTouchButtonAccumulator.getButtonState() + next->buttonState = mTouchButtonAccumulator.getButtonState() | mCursorButtonAccumulator.getButtonState(); - // Sync scroll state. - mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); - mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel(); + // Sync scroll + next->rawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); + next->rawHScroll = mCursorScrollAccumulator.getRelativeHWheel(); mCursorScrollAccumulator.finishSync(); - // Sync touch state. - bool havePointerIds = true; - mCurrentRawPointerData.clear(); - syncTouch(when, &havePointerIds); + // Sync touch + syncTouch(when, next); -#if DEBUG_RAW_EVENTS - if (!havePointerIds) { - ALOGD("syncTouch: pointerCount %d -> %d, no pointer ids", - mLastRawPointerData.pointerCount, - mCurrentRawPointerData.pointerCount); - } else { - ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, " - "hovering ids 0x%08x -> 0x%08x", - mLastRawPointerData.pointerCount, - mCurrentRawPointerData.pointerCount, - mLastRawPointerData.touchingIdBits.value, - mCurrentRawPointerData.touchingIdBits.value, - mLastRawPointerData.hoveringIdBits.value, - mCurrentRawPointerData.hoveringIdBits.value); + // Assign pointer ids. + if (!mHavePointerIds) { + assignPointerIds(last, next); } + +#if DEBUG_RAW_EVENTS + ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, " + "hovering ids 0x%08x -> 0x%08x", + last->rawPointerData.pointerCount, + next->rawPointerData.pointerCount, + last->rawPointerData.touchingIdBits.value, + next->rawPointerData.touchingIdBits.value, + last->rawPointerData.hoveringIdBits.value, + next->rawPointerData.hoveringIdBits.value); #endif - // Reset state that we will compute below. - mCurrentFingerIdBits.clear(); - mCurrentStylusIdBits.clear(); - mCurrentMouseIdBits.clear(); - mCurrentCookedPointerData.clear(); + processRawTouches(false /*timeout*/); +} +void TouchInputMapper::processRawTouches(bool timeout) { if (mDeviceMode == DEVICE_MODE_DISABLED) { // Drop all input if the device is disabled. - mCurrentRawPointerData.clear(); - mCurrentButtonState = 0; - } else { - // Preprocess pointer data. - if (!havePointerIds) { - assignPointerIds(); - } - - // Handle policy on initial down or hover events. - uint32_t policyFlags = 0; - bool initialDown = mLastRawPointerData.pointerCount == 0 - && mCurrentRawPointerData.pointerCount != 0; - bool buttonsPressed = mCurrentButtonState & ~mLastButtonState; - if (initialDown || buttonsPressed) { - // If this is a touch screen, hide the pointer on an initial down. - if (mDeviceMode == DEVICE_MODE_DIRECT) { - getContext()->fadePointer(); - } + mCurrentRawState.clear(); + mRawStatesPending.clear(); + return; + } - if (mParameters.wake) { - policyFlags |= POLICY_FLAG_WAKE; - } + // Drain any pending touch states. The invariant here is that the mCurrentRawState is always + // valid and must go through the full cook and dispatch cycle. This ensures that anything + // touching the current state will only observe the events that have been dispatched to the + // rest of the pipeline. + const size_t N = mRawStatesPending.size(); + size_t count; + for(count = 0; count < N; count++) { + const RawState& next = mRawStatesPending[count]; + + // A failure to assign the stylus id means that we're waiting on stylus data + // and so should defer the rest of the pipeline. + if (assignExternalStylusId(next, timeout)) { + break; } - // Synthesize key down from raw buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, - policyFlags, mLastButtonState, mCurrentButtonState); + // All ready to go. + mExternalStylusDataPending = false; + mCurrentRawState.copyFrom(next); + cookAndDispatch(mCurrentRawState.when); + } + if (count != 0) { + mRawStatesPending.removeItemsAt(0, count); + } + + // TODO: If we still have pending stylus data that hasn't been mapped to a touch yet + // then set a timeout to synthesize a new touch event with the new data. Otherwise + // we will lose button and pressure information while the touch is stationary. + if (mExternalStylusDataPending) { + ALOGD("STYLUS TODO: Wiggle wiggle wiggle."); + } +} - // Consume raw off-screen touches before cooking pointer data. - // If touches are consumed, subsequent code will not receive any pointer data. - if (consumeRawTouches(when, policyFlags)) { - mCurrentRawPointerData.clear(); +void TouchInputMapper::cookAndDispatch(nsecs_t when) { + // Always start with a clean state. + mCurrentCookedState.clear(); + + // Apply stylus buttons to current raw state. + applyExternalStylusButtonState(when); + + // Handle policy on initial down or hover events. + bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 + && mCurrentRawState.rawPointerData.pointerCount != 0; + + uint32_t policyFlags = 0; + bool buttonsPressed = mCurrentRawState.buttonState & ~mLastRawState.buttonState; + if (initialDown || buttonsPressed) { + // If this is a touch screen, hide the pointer on an initial down. + if (mDeviceMode == DEVICE_MODE_DIRECT) { + getContext()->fadePointer(); } - // Cook pointer data. This call populates the mCurrentCookedPointerData structure - // with cooked pointer data that has the same ids and indices as the raw data. - // The following code can use either the raw or cooked data, as needed. - cookPointerData(); + if (mParameters.wake) { + policyFlags |= POLICY_FLAG_WAKE; + } + } - // Dispatch the touches either directly or by translation through a pointer on screen. - if (mDeviceMode == DEVICE_MODE_POINTER) { - for (BitSet32 idBits(mCurrentRawPointerData.touchingIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { - mCurrentStylusIdBits.markBit(id); - } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - mCurrentFingerIdBits.markBit(id); - } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) { - mCurrentMouseIdBits.markBit(id); - } + // Consume raw off-screen touches before cooking pointer data. + // If touches are consumed, subsequent code will not receive any pointer data. + if (consumeRawTouches(when, policyFlags)) { + mCurrentRawState.rawPointerData.clear(); + } + + // Cook pointer data. This call populates the mCurrentCookedState.cookedPointerData structure + // with cooked pointer data that has the same ids and indices as the raw data. + // The following code can use either the raw or cooked data, as needed. + cookPointerData(); + + // Apply stylus pressure to current cooked state. + applyExternalStylusTouchState(when); + + // Synthesize key down from raw buttons if needed. + synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, + policyFlags, mLastRawState.buttonState, mCurrentRawState.buttonState); + + // Dispatch the touches either directly or by translation through a pointer on screen. + if (mDeviceMode == DEVICE_MODE_POINTER) { + for (BitSet32 idBits(mCurrentRawState.rawPointerData.touchingIdBits); + !idBits.isEmpty(); ) { + uint32_t id = idBits.clearFirstMarkedBit(); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); + if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS + || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { + mCurrentCookedState.stylusIdBits.markBit(id); + } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER + || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + mCurrentCookedState.fingerIdBits.markBit(id); + } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) { + mCurrentCookedState.mouseIdBits.markBit(id); } - for (BitSet32 idBits(mCurrentRawPointerData.hoveringIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { - mCurrentStylusIdBits.markBit(id); - } + } + for (BitSet32 idBits(mCurrentRawState.rawPointerData.hoveringIdBits); + !idBits.isEmpty(); ) { + uint32_t id = idBits.clearFirstMarkedBit(); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); + if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS + || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { + mCurrentCookedState.stylusIdBits.markBit(id); } + } - // Stylus takes precedence over all tools, then mouse, then finger. - PointerUsage pointerUsage = mPointerUsage; - if (!mCurrentStylusIdBits.isEmpty()) { - mCurrentMouseIdBits.clear(); - mCurrentFingerIdBits.clear(); - pointerUsage = POINTER_USAGE_STYLUS; - } else if (!mCurrentMouseIdBits.isEmpty()) { - mCurrentFingerIdBits.clear(); - pointerUsage = POINTER_USAGE_MOUSE; - } else if (!mCurrentFingerIdBits.isEmpty() || isPointerDown(mCurrentButtonState)) { - pointerUsage = POINTER_USAGE_GESTURES; - } + // Stylus takes precedence over all tools, then mouse, then finger. + PointerUsage pointerUsage = mPointerUsage; + if (!mCurrentCookedState.stylusIdBits.isEmpty()) { + mCurrentCookedState.mouseIdBits.clear(); + mCurrentCookedState.fingerIdBits.clear(); + pointerUsage = POINTER_USAGE_STYLUS; + } else if (!mCurrentCookedState.mouseIdBits.isEmpty()) { + mCurrentCookedState.fingerIdBits.clear(); + pointerUsage = POINTER_USAGE_MOUSE; + } else if (!mCurrentCookedState.fingerIdBits.isEmpty() || + isPointerDown(mCurrentRawState.buttonState)) { + pointerUsage = POINTER_USAGE_GESTURES; + } - dispatchPointerUsage(when, policyFlags, pointerUsage); - } else { - if (mDeviceMode == DEVICE_MODE_DIRECT - && mConfig.showTouches && mPointerController != NULL) { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT); - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - - mPointerController->setButtonState(mCurrentButtonState); - mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mCurrentCookedPointerData.touchingIdBits); - } + dispatchPointerUsage(when, policyFlags, pointerUsage); + } else { + if (mDeviceMode == DEVICE_MODE_DIRECT + && mConfig.showTouches && mPointerController != NULL) { + mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT); + mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - dispatchHoverExit(when, policyFlags); - dispatchTouches(when, policyFlags); - dispatchHoverEnterAndMove(when, policyFlags); + mPointerController->setButtonState(mCurrentRawState.buttonState); + mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.touchingIdBits); } - // Synthesize key up from raw buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, - policyFlags, mLastButtonState, mCurrentButtonState); + dispatchHoverExit(when, policyFlags); + dispatchTouches(when, policyFlags); + dispatchHoverEnterAndMove(when, policyFlags); } - // Copy current touch to last touch in preparation for the next cycle. - mLastRawPointerData.copyFrom(mCurrentRawPointerData); - mLastCookedPointerData.copyFrom(mCurrentCookedPointerData); - mLastButtonState = mCurrentButtonState; - mLastFingerIdBits = mCurrentFingerIdBits; - mLastStylusIdBits = mCurrentStylusIdBits; - mLastMouseIdBits = mCurrentMouseIdBits; + // Synthesize key up from raw buttons if needed. + synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, + policyFlags, mLastRawState.buttonState, mCurrentRawState.buttonState); // Clear some transient state. - mCurrentRawVScroll = 0; - mCurrentRawHScroll = 0; + mCurrentRawState.rawVScroll = 0; + mCurrentRawState.rawHScroll = 0; + + // Copy current touch to last touch in preparation for the next cycle. + mLastRawState.copyFrom(mCurrentRawState); + mLastCookedState.copyFrom(mCurrentCookedState); +} + +void TouchInputMapper::applyExternalStylusButtonState(nsecs_t when) { + if (mDeviceMode == DEVICE_MODE_DIRECT && hasExternalStylus()) { + mCurrentRawState.buttonState |= mExternalStylusState.buttons; + } +} + +void TouchInputMapper::applyExternalStylusTouchState(nsecs_t when) { + CookedPointerData& cpd = mCurrentCookedState.cookedPointerData; + if (mExternalStylusId != -1 && cpd.isTouching(mExternalStylusId)) { + if (mExternalStylusState.pressure != 0.0f) { + PointerCoords& coords = cpd.editPointerCoordsWithId(mExternalStylusId); + coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, mExternalStylusState.pressure); + } + + PointerProperties& properties = cpd.editPointerPropertiesWithId(mExternalStylusId); + if (mExternalStylusState.toolType != AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + properties.toolType = mExternalStylusState.toolType; + } + } +} + +bool TouchInputMapper::assignExternalStylusId(const RawState& state, bool timeout) { + if (mDeviceMode != DEVICE_MODE_DIRECT || !hasExternalStylus()) { + return false; + } + + const bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 + && state.rawPointerData.pointerCount != 0; + if (initialDown) { + if (mExternalStylusState.pressure != 0.0f) { +#if DEBUG_STYLUS_FUSION + ALOGD("Have both stylus and touch data, beginning fusion"); +#endif + mExternalStylusId = state.rawPointerData.touchingIdBits.firstMarkedBit(); + } else if (timeout) { +#if DEBUG_STYLUS_FUSION + ALOGD("Timeout expired, assuming touch is not a stylus."); +#endif + resetExternalStylus(); + } else { + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + if (mExternalStylusDataTimeout == LLONG_MAX) { + mExternalStylusDataTimeout = now + EXTERNAL_STYLUS_DATA_TIMEOUT; + } +#if DEBUG_STYLUS_FUSION + ALOGD("No stylus data but stylus is connected, requesting timeout " + "(%" PRId64 "ms)", mExternalStylusDataTimeout); +#endif + getContext()->requestTimeoutAtTime(mExternalStylusDataTimeout); + return true; + } + } + + // Check if the stylus pointer has gone up. + if (mExternalStylusId != -1 && + !state.rawPointerData.touchingIdBits.hasBit(mExternalStylusId)) { +#if DEBUG_STYLUS_FUSION + ALOGD("Stylus pointer is going up"); +#endif + mExternalStylusId = -1; + } + + return false; } void TouchInputMapper::timeoutExpired(nsecs_t when) { @@ -3908,13 +4116,32 @@ void TouchInputMapper::timeoutExpired(nsecs_t when) { if (mPointerUsage == POINTER_USAGE_GESTURES) { dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/); } + } else if (mDeviceMode == DEVICE_MODE_DIRECT) { + if (mExternalStylusDataTimeout < when) { + mExternalStylusDataTimeout = LLONG_MAX; + processRawTouches(true /*timeout*/); + } else if (mExternalStylusDataTimeout != LLONG_MAX) { + getContext()->requestTimeoutAtTime(mExternalStylusDataTimeout); + } + } +} + +void TouchInputMapper::updateExternalStylusState(const StylusState& state) { + if (mExternalStylusId != -1 || mExternalStylusDataTimeout != LLONG_MAX) { + // We're either in the middle of a fused stream of data or we're waiting on data before + // dispatching the initial down, so go ahead and dispatch now that we have fresh stylus + // data. + mExternalStylusDataTimeout = LLONG_MAX; + mExternalStylusDataPending = true; + mExternalStylusState.copyFrom(state); + processRawTouches(false /*timeout*/); } } bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { // Check for release of a virtual key. if (mCurrentVirtualKey.down) { - if (mCurrentRawPointerData.touchingIdBits.isEmpty()) { + if (mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { // Pointer went up while virtual key was down. mCurrentVirtualKey.down = false; if (!mCurrentVirtualKey.ignored) { @@ -3929,9 +4156,10 @@ bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { return true; } - if (mCurrentRawPointerData.touchingIdBits.count() == 1) { - uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); + if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) { + uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit(); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) { // Pointer is still within the space of the virtual key. @@ -3956,15 +4184,15 @@ bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { } } - if (mLastRawPointerData.touchingIdBits.isEmpty() - && !mCurrentRawPointerData.touchingIdBits.isEmpty()) { + if (mLastRawState.rawPointerData.touchingIdBits.isEmpty() + && !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { // Pointer just went down. Check for virtual key press or off-screen touches. - uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); + uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit(); + const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id); if (!isPointInsideSurface(pointer.x, pointer.y)) { // If exactly one pointer went down, check for virtual key hit. // Otherwise we will drop the entire stroke. - if (mCurrentRawPointerData.touchingIdBits.count() == 1) { + if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) { const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); if (virtualKey) { mCurrentVirtualKey.down = true; @@ -4004,7 +4232,8 @@ bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { // area and accidentally triggers a virtual key. This often happens when virtual keys // are layed out below the screen near to where the on screen keyboard's space bar // is displayed. - if (mConfig.virtualKeyQuietTime > 0 && !mCurrentRawPointerData.touchingIdBits.isEmpty()) { + if (mConfig.virtualKeyQuietTime > 0 && + !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { mContext->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime); } return false; @@ -4024,10 +4253,10 @@ void TouchInputMapper::dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, } void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { - BitSet32 currentIdBits = mCurrentCookedPointerData.touchingIdBits; - BitSet32 lastIdBits = mLastCookedPointerData.touchingIdBits; + BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits; + BitSet32 lastIdBits = mLastCookedState.cookedPointerData.touchingIdBits; int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentButtonState; + int32_t buttonState = mCurrentRawState.buttonState; if (currentIdBits == lastIdBits) { if (!currentIdBits.isEmpty()) { @@ -4036,9 +4265,9 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } @@ -4053,14 +4282,14 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { // Update last coordinates of pointers that have moved so that we observe the new // pointer positions at the same time as other pointers that have just gone up. bool moveNeeded = updateMovedPointers( - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mLastCookedPointerData.pointerProperties, - mLastCookedPointerData.pointerCoords, - mLastCookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mLastCookedState.cookedPointerData.pointerProperties, + mLastCookedState.cookedPointerData.pointerCoords, + mLastCookedState.cookedPointerData.idToIndex, moveIdBits); - if (buttonState != mLastButtonState) { + if (buttonState != mLastRawState.buttonState) { moveNeeded = true; } @@ -4070,9 +4299,9 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, buttonState, 0, - mLastCookedPointerData.pointerProperties, - mLastCookedPointerData.pointerCoords, - mLastCookedPointerData.idToIndex, + mLastCookedState.cookedPointerData.pointerProperties, + mLastCookedState.cookedPointerData.pointerCoords, + mLastCookedState.cookedPointerData.idToIndex, dispatchedIdBits, upId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); dispatchedIdBits.clearBit(upId); @@ -4085,9 +4314,9 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value); dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } @@ -4104,9 +4333,9 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits, downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } @@ -4115,57 +4344,60 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { void TouchInputMapper::dispatchHoverExit(nsecs_t when, uint32_t policyFlags) { if (mSentHoverEnter && - (mCurrentCookedPointerData.hoveringIdBits.isEmpty() - || !mCurrentCookedPointerData.touchingIdBits.isEmpty())) { + (mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty() + || !mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty())) { int32_t metaState = getContext()->getGlobalMetaState(); dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0, - mLastCookedPointerData.pointerProperties, - mLastCookedPointerData.pointerCoords, - mLastCookedPointerData.idToIndex, - mLastCookedPointerData.hoveringIdBits, -1, + AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastRawState.buttonState, 0, + mLastCookedState.cookedPointerData.pointerProperties, + mLastCookedState.cookedPointerData.pointerCoords, + mLastCookedState.cookedPointerData.idToIndex, + mLastCookedState.cookedPointerData.hoveringIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); mSentHoverEnter = false; } } void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags) { - if (mCurrentCookedPointerData.touchingIdBits.isEmpty() - && !mCurrentCookedPointerData.hoveringIdBits.isEmpty()) { + if (mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty() + && !mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty()) { int32_t metaState = getContext()->getGlobalMetaState(); if (!mSentHoverEnter) { - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mCurrentCookedPointerData.hoveringIdBits, -1, + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_ENTER, + 0, metaState, mCurrentRawState.buttonState, 0, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.hoveringIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); mSentHoverEnter = true; } dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mCurrentCookedPointerData.hoveringIdBits, -1, + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, + mCurrentRawState.buttonState, 0, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.hoveringIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } } void TouchInputMapper::cookPointerData() { - uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount; + uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount; - mCurrentCookedPointerData.clear(); - mCurrentCookedPointerData.pointerCount = currentPointerCount; - mCurrentCookedPointerData.hoveringIdBits = mCurrentRawPointerData.hoveringIdBits; - mCurrentCookedPointerData.touchingIdBits = mCurrentRawPointerData.touchingIdBits; + mCurrentCookedState.cookedPointerData.clear(); + mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount; + mCurrentCookedState.cookedPointerData.hoveringIdBits = + mCurrentRawState.rawPointerData.hoveringIdBits; + mCurrentCookedState.cookedPointerData.touchingIdBits = + mCurrentRawState.rawPointerData.touchingIdBits; // Walk through the the active pointers and map device coordinates onto // surface coordinates and adjust for display orientation. for (uint32_t i = 0; i < currentPointerCount; i++) { - const RawPointerData::Pointer& in = mCurrentRawPointerData.pointers[i]; + const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i]; // Size float touchMajor, touchMinor, toolMajor, toolMinor, size; @@ -4204,7 +4436,8 @@ void TouchInputMapper::cookPointerData() { } if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) { - uint32_t touchingCount = mCurrentRawPointerData.touchingIdBits.count(); + uint32_t touchingCount = + mCurrentRawState.rawPointerData.touchingIdBits.count(); if (touchingCount > 1) { touchMajor /= touchingCount; touchMinor /= touchingCount; @@ -4373,7 +4606,7 @@ void TouchInputMapper::cookPointerData() { } // Write output coords. - PointerCoords& out = mCurrentCookedPointerData.pointerCoords[i]; + PointerCoords& out = mCurrentCookedState.cookedPointerData.pointerCoords[i]; out.clear(); out.setAxisValue(AMOTION_EVENT_AXIS_X, x); out.setAxisValue(AMOTION_EVENT_AXIS_Y, y); @@ -4395,14 +4628,15 @@ void TouchInputMapper::cookPointerData() { } // Write output properties. - PointerProperties& properties = mCurrentCookedPointerData.pointerProperties[i]; + PointerProperties& properties = + mCurrentCookedState.cookedPointerData.pointerProperties[i]; uint32_t id = in.id; properties.clear(); properties.id = id; properties.toolType = in.toolType; // Write id index. - mCurrentCookedPointerData.idToIndex[id] = i; + mCurrentCookedState.cookedPointerData.idToIndex[id] = i; } } @@ -4506,7 +4740,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag // Send events! int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentButtonState; + int32_t buttonState = mCurrentRawState.buttonState; // Update last coordinates of pointers that have moved so that we observe the new // pointer positions at the same time as other pointers that have just gone up. @@ -4527,7 +4761,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, movedGestureIdBits); - if (buttonState != mLastButtonState) { + if (buttonState != mLastRawState.buttonState) { moveNeeded = true; } } @@ -4658,7 +4892,7 @@ void TouchInputMapper::abortPointerGestures(nsecs_t when, uint32_t policyFlags) // Cancel previously dispatches pointers. if (!mPointerGesture.lastGestureIdBits.isEmpty()) { int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentButtonState; + int32_t buttonState = mCurrentRawState.buttonState; dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, @@ -4715,21 +4949,22 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, return false; } - const uint32_t currentFingerCount = mCurrentFingerIdBits.count(); - const uint32_t lastFingerCount = mLastFingerIdBits.count(); + const uint32_t currentFingerCount = mCurrentCookedState.fingerIdBits.count(); + const uint32_t lastFingerCount = mLastCookedState.fingerIdBits.count(); // Update the velocity tracker. { VelocityTracker::Position positions[MAX_POINTERS]; uint32_t count = 0; - for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); count++) { + for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); count++) { uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); positions[count].x = pointer.x * mPointerXMovementScale; positions[count].y = pointer.y * mPointerYMovementScale; } mPointerGesture.velocityTracker.addMovement(when, - mCurrentFingerIdBits, positions); + mCurrentCookedState.fingerIdBits, positions); } // If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning @@ -4749,17 +4984,17 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, int32_t lastActiveTouchId = mPointerGesture.activeTouchId; int32_t activeTouchId = lastActiveTouchId; if (activeTouchId < 0) { - if (!mCurrentFingerIdBits.isEmpty()) { + if (!mCurrentCookedState.fingerIdBits.isEmpty()) { activeTouchChanged = true; activeTouchId = mPointerGesture.activeTouchId = - mCurrentFingerIdBits.firstMarkedBit(); + mCurrentCookedState.fingerIdBits.firstMarkedBit(); mPointerGesture.firstTouchTime = when; } - } else if (!mCurrentFingerIdBits.hasBit(activeTouchId)) { + } else if (!mCurrentCookedState.fingerIdBits.hasBit(activeTouchId)) { activeTouchChanged = true; - if (!mCurrentFingerIdBits.isEmpty()) { + if (!mCurrentCookedState.fingerIdBits.isEmpty()) { activeTouchId = mPointerGesture.activeTouchId = - mCurrentFingerIdBits.firstMarkedBit(); + mCurrentCookedState.fingerIdBits.firstMarkedBit(); } else { activeTouchId = mPointerGesture.activeTouchId = -1; } @@ -4782,7 +5017,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, isQuietTime = true; } else if (mPointerGesture.lastGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG && currentFingerCount >= 2 - && !isPointerDown(mCurrentButtonState)) { + && !isPointerDown(mCurrentRawState.buttonState)) { // Enter quiet time when releasing the button and there are still two or more // fingers down. This may indicate that one finger was used to press the button // but it has not gone up yet. @@ -4810,7 +5045,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureIdBits.clear(); mPointerVelocityControl.reset(); - } else if (isPointerDown(mCurrentButtonState)) { + } else if (isPointerDown(mCurrentRawState.buttonState)) { // Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG) // The pointer follows the active touch point. // Emit DOWN, MOVE, UP events at the pointer location. @@ -4839,7 +5074,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, if (activeTouchId >= 0 && currentFingerCount > 1) { int32_t bestId = -1; float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed; - for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); ) { + for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); ) { uint32_t id = idBits.clearFirstMarkedBit(); float vx, vy; if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) { @@ -4860,11 +5095,11 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } } - if (activeTouchId >= 0 && mLastFingerIdBits.hasBit(activeTouchId)) { + if (activeTouchId >= 0 && mLastCookedState.fingerIdBits.hasBit(activeTouchId)) { const RawPointerData::Pointer& currentPointer = - mCurrentRawPointerData.pointerForId(activeTouchId); + mCurrentRawState.rawPointerData.pointerForId(activeTouchId); const RawPointerData::Pointer& lastPointer = - mLastRawPointerData.pointerForId(activeTouchId); + mLastRawState.rawPointerData.pointerForId(activeTouchId); float deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; float deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; @@ -5000,11 +5235,11 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; } - if (mLastFingerIdBits.hasBit(activeTouchId)) { + if (mLastCookedState.fingerIdBits.hasBit(activeTouchId)) { const RawPointerData::Pointer& currentPointer = - mCurrentRawPointerData.pointerForId(activeTouchId); + mCurrentRawState.rawPointerData.pointerForId(activeTouchId); const RawPointerData::Pointer& lastPointer = - mLastRawPointerData.pointerForId(activeTouchId); + mLastRawState.rawPointerData.pointerForId(activeTouchId); float deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; float deltaY = (currentPointer.y - lastPointer.y) @@ -5109,7 +5344,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, + mConfig.pointerGestureMultitouchSettleInterval - when) * 0.000001f); #endif - mCurrentRawPointerData.getCentroidOfTouchingPointers( + mCurrentRawState.rawPointerData.getCentroidOfTouchingPointers( &mPointerGesture.referenceTouchX, &mPointerGesture.referenceTouchY); mPointerController->getPosition(&mPointerGesture.referenceGestureX, @@ -5117,23 +5352,23 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } // Clear the reference deltas for fingers not yet included in the reference calculation. - for (BitSet32 idBits(mCurrentFingerIdBits.value + for (BitSet32 idBits(mCurrentCookedState.fingerIdBits.value & ~mPointerGesture.referenceIdBits.value); !idBits.isEmpty(); ) { uint32_t id = idBits.clearFirstMarkedBit(); mPointerGesture.referenceDeltas[id].dx = 0; mPointerGesture.referenceDeltas[id].dy = 0; } - mPointerGesture.referenceIdBits = mCurrentFingerIdBits; + mPointerGesture.referenceIdBits = mCurrentCookedState.fingerIdBits; // Add delta for all fingers and calculate a common movement delta. float commonDeltaX = 0, commonDeltaY = 0; - BitSet32 commonIdBits(mLastFingerIdBits.value - & mCurrentFingerIdBits.value); + BitSet32 commonIdBits(mLastCookedState.fingerIdBits.value + & mCurrentCookedState.fingerIdBits.value); for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) { bool first = (idBits == commonIdBits); uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& cpd = mCurrentRawPointerData.pointerForId(id); - const RawPointerData::Pointer& lpd = mLastRawPointerData.pointerForId(id); + const RawPointerData::Pointer& cpd = mCurrentRawState.rawPointerData.pointerForId(id); + const RawPointerData::Pointer& lpd = mLastRawState.rawPointerData.pointerForId(id); PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; delta.dx += cpd.x - lpd.x; delta.dy += cpd.y - lpd.y; @@ -5174,11 +5409,13 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; } else { // There are exactly two pointers. - BitSet32 idBits(mCurrentFingerIdBits); + BitSet32 idBits(mCurrentCookedState.fingerIdBits); uint32_t id1 = idBits.clearFirstMarkedBit(); uint32_t id2 = idBits.firstMarkedBit(); - const RawPointerData::Pointer& p1 = mCurrentRawPointerData.pointerForId(id1); - const RawPointerData::Pointer& p2 = mCurrentRawPointerData.pointerForId(id2); + const RawPointerData::Pointer& p1 = + mCurrentRawState.rawPointerData.pointerForId(id1); + const RawPointerData::Pointer& p2 = + mCurrentRawState.rawPointerData.pointerForId(id2); float mutualDistance = distance(p1.x, p1.y, p2.x, p2.y); if (mutualDistance > mPointerGestureMaxSwipeWidth) { // There are two pointers but they are too far apart for a SWIPE, @@ -5324,14 +5561,14 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } else { // Otherwise, assume we mapped all touches from the previous frame. // Reuse all mappings that are still applicable. - mappedTouchIdBits.value = mLastFingerIdBits.value - & mCurrentFingerIdBits.value; + mappedTouchIdBits.value = mLastCookedState.fingerIdBits.value + & mCurrentCookedState.fingerIdBits.value; usedGestureIdBits = mPointerGesture.lastGestureIdBits; // Check whether we need to choose a new active gesture id because the // current went went up. - for (BitSet32 upTouchIdBits(mLastFingerIdBits.value - & ~mCurrentFingerIdBits.value); + for (BitSet32 upTouchIdBits(mLastCookedState.fingerIdBits.value + & ~mCurrentCookedState.fingerIdBits.value); !upTouchIdBits.isEmpty(); ) { uint32_t upTouchId = upTouchIdBits.clearFirstMarkedBit(); uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId]; @@ -5350,7 +5587,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.activeGestureId); #endif - BitSet32 idBits(mCurrentFingerIdBits); + BitSet32 idBits(mCurrentCookedState.fingerIdBits); for (uint32_t i = 0; i < currentFingerCount; i++) { uint32_t touchId = idBits.clearFirstMarkedBit(); uint32_t gestureId; @@ -5374,7 +5611,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureIdToIndex[gestureId] = i; const RawPointerData::Pointer& pointer = - mCurrentRawPointerData.pointerForId(touchId); + mCurrentRawState.rawPointerData.pointerForId(touchId); float deltaX = (pointer.x - mPointerGesture.referenceTouchX) * mPointerXZoomScale; float deltaY = (pointer.y - mPointerGesture.referenceTouchY) @@ -5405,7 +5642,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } } - mPointerController->setButtonState(mCurrentButtonState); + mPointerController->setButtonState(mCurrentRawState.buttonState); #if DEBUG_GESTURES ALOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, " @@ -5447,23 +5684,24 @@ void TouchInputMapper::dispatchPointerStylus(nsecs_t when, uint32_t policyFlags) mPointerSimple.currentProperties.clear(); bool down, hovering; - if (!mCurrentStylusIdBits.isEmpty()) { - uint32_t id = mCurrentStylusIdBits.firstMarkedBit(); - uint32_t index = mCurrentCookedPointerData.idToIndex[id]; - float x = mCurrentCookedPointerData.pointerCoords[index].getX(); - float y = mCurrentCookedPointerData.pointerCoords[index].getY(); + if (!mCurrentCookedState.stylusIdBits.isEmpty()) { + uint32_t id = mCurrentCookedState.stylusIdBits.firstMarkedBit(); + uint32_t index = mCurrentCookedState.cookedPointerData.idToIndex[id]; + float x = mCurrentCookedState.cookedPointerData.pointerCoords[index].getX(); + float y = mCurrentCookedState.cookedPointerData.pointerCoords[index].getY(); mPointerController->setPosition(x, y); - hovering = mCurrentCookedPointerData.hoveringIdBits.hasBit(id); + hovering = mCurrentCookedState.cookedPointerData.hoveringIdBits.hasBit(id); down = !hovering; mPointerController->getPosition(&x, &y); - mPointerSimple.currentCoords.copyFrom(mCurrentCookedPointerData.pointerCoords[index]); + mPointerSimple.currentCoords.copyFrom( + mCurrentCookedState.cookedPointerData.pointerCoords[index]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); mPointerSimple.currentProperties.id = 0; mPointerSimple.currentProperties.toolType = - mCurrentCookedPointerData.pointerProperties[index].toolType; + mCurrentCookedState.cookedPointerData.pointerProperties[index].toolType; } else { down = false; hovering = false; @@ -5481,16 +5719,16 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags) mPointerSimple.currentProperties.clear(); bool down, hovering; - if (!mCurrentMouseIdBits.isEmpty()) { - uint32_t id = mCurrentMouseIdBits.firstMarkedBit(); - uint32_t currentIndex = mCurrentRawPointerData.idToIndex[id]; - if (mLastMouseIdBits.hasBit(id)) { - uint32_t lastIndex = mCurrentRawPointerData.idToIndex[id]; - float deltaX = (mCurrentRawPointerData.pointers[currentIndex].x - - mLastRawPointerData.pointers[lastIndex].x) + if (!mCurrentCookedState.mouseIdBits.isEmpty()) { + uint32_t id = mCurrentCookedState.mouseIdBits.firstMarkedBit(); + uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id]; + if (mLastCookedState.mouseIdBits.hasBit(id)) { + uint32_t lastIndex = mCurrentRawState.rawPointerData.idToIndex[id]; + float deltaX = (mCurrentRawState.rawPointerData.pointers[currentIndex].x + - mLastRawState.rawPointerData.pointers[lastIndex].x) * mPointerXMovementScale; - float deltaY = (mCurrentRawPointerData.pointers[currentIndex].y - - mLastRawPointerData.pointers[lastIndex].y) + float deltaY = (mCurrentRawState.rawPointerData.pointers[currentIndex].y + - mLastRawState.rawPointerData.pointers[lastIndex].y) * mPointerYMovementScale; rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); @@ -5501,20 +5739,20 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags) mPointerVelocityControl.reset(); } - down = isPointerDown(mCurrentButtonState); + down = isPointerDown(mCurrentRawState.buttonState); hovering = !down; float x, y; mPointerController->getPosition(&x, &y); mPointerSimple.currentCoords.copyFrom( - mCurrentCookedPointerData.pointerCoords[currentIndex]); + mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, hovering ? 0.0f : 1.0f); mPointerSimple.currentProperties.id = 0; mPointerSimple.currentProperties.toolType = - mCurrentCookedPointerData.pointerProperties[currentIndex].toolType; + mCurrentCookedState.cookedPointerData.pointerProperties[currentIndex].toolType; } else { mPointerVelocityControl.reset(); @@ -5539,7 +5777,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, if (down || hovering) { mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); mPointerController->clearSpots(); - mPointerController->setButtonState(mCurrentButtonState); + mPointerController->setButtonState(mCurrentRawState.buttonState); mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) { mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); @@ -5551,7 +5789,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send up. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_UP, 0, metaState, mLastButtonState, 0, + AMOTION_EVENT_ACTION_UP, 0, metaState, mLastRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5564,7 +5802,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send hover exit. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0, + AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5579,7 +5817,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send down. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_DOWN, 0, metaState, mCurrentButtonState, 0, + AMOTION_EVENT_ACTION_DOWN, 0, metaState, mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5589,7 +5827,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send move. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, mCurrentButtonState, 0, + AMOTION_EVENT_ACTION_MOVE, 0, metaState, mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5603,7 +5841,8 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send hover enter. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0, + AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, + mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5613,7 +5852,8 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send hover move. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0, + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, + mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5621,9 +5861,9 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, getListener()->notifyMotion(&args); } - if (mCurrentRawVScroll || mCurrentRawHScroll) { - float vscroll = mCurrentRawVScroll; - float hscroll = mCurrentRawHScroll; + if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) { + float vscroll = mCurrentRawState.rawVScroll; + float hscroll = mCurrentRawState.rawHScroll; mWheelYVelocityControl.move(when, NULL, &vscroll); mWheelXVelocityControl.move(when, &hscroll, NULL); @@ -5634,7 +5874,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, metaState, mCurrentButtonState, 0, + AMOTION_EVENT_ACTION_SCROLL, 0, metaState, mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &pointerCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5768,11 +6008,11 @@ const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit( return NULL; } -void TouchInputMapper::assignPointerIds() { - uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount; - uint32_t lastPointerCount = mLastRawPointerData.pointerCount; +void TouchInputMapper::assignPointerIds(const RawState* last, RawState* current) { + uint32_t currentPointerCount = current->rawPointerData.pointerCount; + uint32_t lastPointerCount = last->rawPointerData.pointerCount; - mCurrentRawPointerData.clearIdBits(); + current->rawPointerData.clearIdBits(); if (currentPointerCount == 0) { // No pointers to assign. @@ -5783,21 +6023,21 @@ void TouchInputMapper::assignPointerIds() { // All pointers are new. for (uint32_t i = 0; i < currentPointerCount; i++) { uint32_t id = i; - mCurrentRawPointerData.pointers[i].id = id; - mCurrentRawPointerData.idToIndex[id] = i; - mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(i)); + current->rawPointerData.pointers[i].id = id; + current->rawPointerData.idToIndex[id] = i; + current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(i)); } return; } if (currentPointerCount == 1 && lastPointerCount == 1 - && mCurrentRawPointerData.pointers[0].toolType - == mLastRawPointerData.pointers[0].toolType) { + && current->rawPointerData.pointers[0].toolType + == last->rawPointerData.pointers[0].toolType) { // Only one pointer and no change in count so it must have the same id as before. - uint32_t id = mLastRawPointerData.pointers[0].id; - mCurrentRawPointerData.pointers[0].id = id; - mCurrentRawPointerData.idToIndex[id] = 0; - mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(0)); + uint32_t id = last->rawPointerData.pointers[0].id; + current->rawPointerData.pointers[0].id = id; + current->rawPointerData.idToIndex[id] = 0; + current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(0)); return; } @@ -5815,9 +6055,9 @@ void TouchInputMapper::assignPointerIds() { for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount; lastPointerIndex++) { const RawPointerData::Pointer& currentPointer = - mCurrentRawPointerData.pointers[currentPointerIndex]; + current->rawPointerData.pointers[currentPointerIndex]; const RawPointerData::Pointer& lastPointer = - mLastRawPointerData.pointers[lastPointerIndex]; + last->rawPointerData.pointers[lastPointerIndex]; if (currentPointer.toolType == lastPointer.toolType) { int64_t deltaX = currentPointer.x - lastPointer.x; int64_t deltaY = currentPointer.y - lastPointer.y; @@ -5923,11 +6163,11 @@ void TouchInputMapper::assignPointerIds() { matchedCurrentBits.markBit(currentPointerIndex); matchedLastBits.markBit(lastPointerIndex); - uint32_t id = mLastRawPointerData.pointers[lastPointerIndex].id; - mCurrentRawPointerData.pointers[currentPointerIndex].id = id; - mCurrentRawPointerData.idToIndex[id] = currentPointerIndex; - mCurrentRawPointerData.markIdBit(id, - mCurrentRawPointerData.isHovering(currentPointerIndex)); + uint32_t id = last->rawPointerData.pointers[lastPointerIndex].id; + current->rawPointerData.pointers[currentPointerIndex].id = id; + current->rawPointerData.idToIndex[id] = currentPointerIndex; + current->rawPointerData.markIdBit(id, + current->rawPointerData.isHovering(currentPointerIndex)); usedIdBits.markBit(id); #if DEBUG_POINTER_ASSIGNMENT @@ -5943,10 +6183,10 @@ void TouchInputMapper::assignPointerIds() { uint32_t currentPointerIndex = matchedCurrentBits.markFirstUnmarkedBit(); uint32_t id = usedIdBits.markFirstUnmarkedBit(); - mCurrentRawPointerData.pointers[currentPointerIndex].id = id; - mCurrentRawPointerData.idToIndex[id] = currentPointerIndex; - mCurrentRawPointerData.markIdBit(id, - mCurrentRawPointerData.isHovering(currentPointerIndex)); + current->rawPointerData.pointers[currentPointerIndex].id = id; + current->rawPointerData.idToIndex[id] = currentPointerIndex; + current->rawPointerData.markIdBit(id, + current->rawPointerData.isHovering(currentPointerIndex)); #if DEBUG_POINTER_ASSIGNMENT ALOGD("assignPointerIds - assigned: cur=%d, id=%d", @@ -6025,18 +6265,18 @@ void SingleTouchInputMapper::process(const RawEvent* rawEvent) { mSingleTouchMotionAccumulator.process(rawEvent); } -void SingleTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { +void SingleTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { if (mTouchButtonAccumulator.isToolActive()) { - mCurrentRawPointerData.pointerCount = 1; - mCurrentRawPointerData.idToIndex[0] = 0; + outState->rawPointerData.pointerCount = 1; + outState->rawPointerData.idToIndex[0] = 0; bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE && (mTouchButtonAccumulator.isHovering() || (mRawPointerAxes.pressure.valid && mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0)); - mCurrentRawPointerData.markIdBit(0, isHovering); + outState->rawPointerData.markIdBit(0, isHovering); - RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[0]; + RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[0]; outPointer.id = 0; outPointer.x = mSingleTouchMotionAccumulator.getAbsoluteX(); outPointer.y = mSingleTouchMotionAccumulator.getAbsoluteY(); @@ -6097,7 +6337,7 @@ void MultiTouchInputMapper::process(const RawEvent* rawEvent) { mMultiTouchMotionAccumulator.process(rawEvent); } -void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { +void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { size_t inCount = mMultiTouchMotionAccumulator.getSlotCount(); size_t outCount = 0; BitSet32 newPointerIdBits; @@ -6118,7 +6358,7 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { break; // too many fingers! } - RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[outCount]; + RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount]; outPointer.x = inSlot->getX(); outPointer.y = inSlot->getY(); outPointer.pressure = inSlot->getPressure(); @@ -6145,38 +6385,37 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { outPointer.isHovering = isHovering; // Assign pointer id using tracking id if available. - if (*outHavePointerIds) { - int32_t trackingId = inSlot->getTrackingId(); - int32_t id = -1; - if (trackingId >= 0) { - for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) { - uint32_t n = idBits.clearFirstMarkedBit(); - if (mPointerTrackingIdMap[n] == trackingId) { - id = n; - } - } - - if (id < 0 && !mPointerIdBits.isFull()) { - id = mPointerIdBits.markFirstUnmarkedBit(); - mPointerTrackingIdMap[id] = trackingId; + mHavePointerIds = true; + int32_t trackingId = inSlot->getTrackingId(); + int32_t id = -1; + if (trackingId >= 0) { + for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) { + uint32_t n = idBits.clearFirstMarkedBit(); + if (mPointerTrackingIdMap[n] == trackingId) { + id = n; } } - if (id < 0) { - *outHavePointerIds = false; - mCurrentRawPointerData.clearIdBits(); - newPointerIdBits.clear(); - } else { - outPointer.id = id; - mCurrentRawPointerData.idToIndex[id] = outCount; - mCurrentRawPointerData.markIdBit(id, isHovering); - newPointerIdBits.markBit(id); + + if (id < 0 && !mPointerIdBits.isFull()) { + id = mPointerIdBits.markFirstUnmarkedBit(); + mPointerTrackingIdMap[id] = trackingId; } } + if (id < 0) { + mHavePointerIds = false; + outState->rawPointerData.clearIdBits(); + newPointerIdBits.clear(); + } else { + outPointer.id = id; + outState->rawPointerData.idToIndex[id] = outCount; + outState->rawPointerData.markIdBit(id, isHovering); + newPointerIdBits.markBit(id); + } outCount += 1; } - mCurrentRawPointerData.pointerCount = outCount; + outState->rawPointerData.pointerCount = outCount; mPointerIdBits = newPointerIdBits; mMultiTouchMotionAccumulator.finishSync(); @@ -6220,6 +6459,73 @@ bool MultiTouchInputMapper::hasStylus() const { || mTouchButtonAccumulator.hasStylus(); } +// --- ExternalStylusInputMapper + +ExternalStylusInputMapper::ExternalStylusInputMapper(InputDevice* device) : + InputMapper(device) { + +} + +uint32_t ExternalStylusInputMapper::getSources() { + return AINPUT_SOURCE_STYLUS; +} + +void ExternalStylusInputMapper::populateDeviceInfo(InputDeviceInfo* info) { + InputMapper::populateDeviceInfo(info); + info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, AINPUT_SOURCE_STYLUS, + 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); +} + +void ExternalStylusInputMapper::dump(String8& dump) { + dump.append(INDENT2 "External Stylus Input Mapper:\n"); + dump.append(INDENT3 "Raw Stylus Axes:\n"); + dumpRawAbsoluteAxisInfo(dump, mRawPressureAxis, "Pressure"); + dump.append(INDENT3 "Stylus State:\n"); + dumpStylusState(dump, mStylusState); +} + +void ExternalStylusInputMapper::configure(nsecs_t when, + const InputReaderConfiguration* config, uint32_t changes) { + getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPressureAxis); + mTouchButtonAccumulator.configure(getDevice()); +} + +void ExternalStylusInputMapper::reset(nsecs_t when) { + InputDevice* device = getDevice(); + mSingleTouchMotionAccumulator.reset(device); + mTouchButtonAccumulator.reset(device); + InputMapper::reset(when); +} + +void ExternalStylusInputMapper::process(const RawEvent* rawEvent) { + mSingleTouchMotionAccumulator.process(rawEvent); + mTouchButtonAccumulator.process(rawEvent); + + if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { + sync(rawEvent->when); + } +} + +void ExternalStylusInputMapper::sync(nsecs_t when) { + mStylusState.clear(); + + mStylusState.when = when; + + int32_t pressure = mSingleTouchMotionAccumulator.getAbsolutePressure(); + if (mRawPressureAxis.valid) { + mStylusState.pressure = float(pressure) / mRawPressureAxis.maxValue; + } else if (mTouchButtonAccumulator.isToolActive()) { + mStylusState.pressure = 1.0f; + } else { + mStylusState.pressure = 0.0f; + } + + mStylusState.buttons = mTouchButtonAccumulator.getButtonState(); + mStylusState.toolType = mTouchButtonAccumulator.getToolType(); + + mContext->dispatchExternalStylusState(mStylusState); +} + // --- JoystickInputMapper --- diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h index 7a514e0..baff7fa 100644 --- a/services/inputflinger/InputReader.h +++ b/services/inputflinger/InputReader.h @@ -139,7 +139,10 @@ struct InputReaderConfiguration { CHANGE_DEVICE_ALIAS = 1 << 5, // The location calibration matrix changed. - TOUCH_AFFINE_TRANSFORMATION = 1 << 6, + CHANGE_TOUCH_AFFINE_TRANSFORMATION = 1 << 6, + + // The presence of an external stylus has changed. + CHANGE_EXTERNAL_STYLUS_PRESENCE = 1 << 7, // All devices must be reopened. CHANGE_MUST_REOPEN = 1 << 31, @@ -371,6 +374,31 @@ public: virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0; }; +struct StylusState { + /* Time the stylus event was received. */ + nsecs_t when; + /* Pressure as reported by the stylus, normalized to the range [0, 1.0]. */ + float pressure; + /* The state of the stylus buttons as a bitfield (e.g. AMOTION_EVENT_BUTTON_SECONDARY). */ + uint32_t buttons; + /* Which tool type the stylus is currently using (e.g. AMOTION_EVENT_TOOL_TYPE_ERASER). */ + int32_t toolType; + + void copyFrom(const StylusState& other) { + when = other.when; + pressure = other.pressure; + buttons = other.buttons; + toolType = other.toolType; + } + + void clear() { + when = LLONG_MAX; + pressure = 0.f; + buttons = 0; + toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; + } +}; + /* Internal interface used by individual input devices to access global input device state * and parameters maintained by the input reader. @@ -392,6 +420,9 @@ public: virtual void requestTimeoutAtTime(nsecs_t when) = 0; virtual int32_t bumpGeneration() = 0; + virtual void getExternalStylusDevices(Vector& outDevices); + virtual void dispatchExternalStylusState(const StylusState& outState); + virtual InputReaderPolicyInterface* getPolicy() = 0; virtual InputListenerInterface* getListener() = 0; virtual EventHubInterface* getEventHub() = 0; @@ -458,6 +489,8 @@ protected: virtual void fadePointer(); virtual void requestTimeoutAtTime(nsecs_t when); virtual int32_t bumpGeneration(); + virtual void getExternalStylusDevices(Vector& outDevices); + virtual void dispatchExternalStylusState(const StylusState& outState); virtual InputReaderPolicyInterface* getPolicy(); virtual InputListenerInterface* getListener(); virtual EventHubInterface* getEventHub(); @@ -496,6 +529,10 @@ private: void updateGlobalMetaStateLocked(); int32_t getGlobalMetaStateLocked(); + void notifyExternalStylusPresenceChanged(); + void getExternalStylusDevicesLocked(Vector& outDevices); + void dispatchExternalStylusState(const StylusState& state); + void fadePointerLocked(); int32_t mGeneration; @@ -566,6 +603,7 @@ public: void reset(nsecs_t when); void process(const RawEvent* rawEvents, size_t count); void timeoutExpired(nsecs_t when); + void updateExternalStylusState(const StylusState& state); void getDeviceInfo(InputDeviceInfo* outDeviceInfo); int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); @@ -835,9 +873,21 @@ struct CookedPointerData { return pointerCoords[idToIndex[id]]; } + inline PointerCoords& editPointerCoordsWithId(uint32_t id) { + return pointerCoords[idToIndex[id]]; + } + + inline PointerProperties& editPointerPropertiesWithId(uint32_t id) { + return pointerProperties[idToIndex[id]]; + } + inline bool isHovering(uint32_t pointerIndex) { return hoveringIdBits.hasBit(pointerProperties[pointerIndex].id); } + + inline bool isTouching(uint32_t pointerIndex) { + return touchingIdBits.hasBit(pointerProperties[pointerIndex].id); + } }; @@ -982,6 +1032,8 @@ public: virtual int32_t getMetaState(); + virtual void updateExternalStylusState(const StylusState& state); + virtual void fadePointer(); protected: @@ -993,6 +1045,7 @@ protected: static void dumpRawAbsoluteAxisInfo(String8& dump, const RawAbsoluteAxisInfo& axis, const char* name); + static void dumpStylusState(String8& dump, const StylusState& state); }; @@ -1199,6 +1252,7 @@ public: virtual void fadePointer(); virtual void cancelTouch(nsecs_t when); virtual void timeoutExpired(nsecs_t when); + virtual void updateExternalStylusState(const StylusState& state); protected: CursorButtonAccumulator mCursorButtonAccumulator; @@ -1338,36 +1392,79 @@ protected: // Affine location transformation/calibration struct TouchAffineTransformation mAffineTransform; - // Raw pointer axis information from the driver. RawPointerAxes mRawPointerAxes; - // Raw pointer sample data. - RawPointerData mCurrentRawPointerData; - RawPointerData mLastRawPointerData; + struct RawState { + nsecs_t when; + + // Raw pointer sample data. + RawPointerData rawPointerData; + + int32_t buttonState; + + // Scroll state. + int32_t rawVScroll; + int32_t rawHScroll; + + void copyFrom(const RawState& other) { + when = other.when; + rawPointerData.copyFrom(other.rawPointerData); + buttonState = other.buttonState; + rawVScroll = other.rawVScroll; + rawHScroll = other.rawHScroll; + } + + void clear() { + when = 0; + rawPointerData.clear(); + buttonState = 0; + rawVScroll = 0; + rawHScroll = 0; + } + }; + + struct CookedState { + // Cooked pointer sample data. + CookedPointerData cookedPointerData; - // Cooked pointer sample data. - CookedPointerData mCurrentCookedPointerData; - CookedPointerData mLastCookedPointerData; + // Id bits used to differentiate fingers, stylus and mouse tools. + BitSet32 fingerIdBits; + BitSet32 stylusIdBits; + BitSet32 mouseIdBits; - // Button state. - int32_t mCurrentButtonState; - int32_t mLastButtonState; + void copyFrom(const CookedState& other) { + cookedPointerData.copyFrom(other.cookedPointerData); + fingerIdBits = other.fingerIdBits; + stylusIdBits = other.stylusIdBits; + mouseIdBits = other.mouseIdBits; + } - // Scroll state. - int32_t mCurrentRawVScroll; - int32_t mCurrentRawHScroll; + void clear() { + cookedPointerData.clear(); + fingerIdBits.clear(); + stylusIdBits.clear(); + mouseIdBits.clear(); + } + }; - // Id bits used to differentiate fingers, stylus and mouse tools. - BitSet32 mCurrentFingerIdBits; // finger or unknown - BitSet32 mLastFingerIdBits; - BitSet32 mCurrentStylusIdBits; // stylus or eraser - BitSet32 mLastStylusIdBits; - BitSet32 mCurrentMouseIdBits; // mouse or lens - BitSet32 mLastMouseIdBits; + Vector mRawStatesPending; + RawState mCurrentRawState; + CookedState mCurrentCookedState; + RawState mLastRawState; + CookedState mLastCookedState; + + // State provided by an external stylus + StylusState mExternalStylusState; + int64_t mExternalStylusId; + nsecs_t mExternalStylusDataTimeout; + bool mExternalStylusDataPending; // True if we sent a HOVER_ENTER event. bool mSentHoverEnter; + // Have we assigned pointer IDs for this stream + bool mHavePointerIds; + // The time the primary pointer last went down. nsecs_t mDownTime; @@ -1387,11 +1484,13 @@ protected: virtual void parseCalibration(); virtual void resolveCalibration(); virtual void dumpCalibration(String8& dump); + virtual void updateAffineTransformation(); virtual void dumpAffineTransformation(String8& dump); + virtual void resolveExternalStylusPresence(); virtual bool hasStylus() const = 0; - virtual void updateAffineTransformation(); + virtual bool hasExternalStylus() const; - virtual void syncTouch(nsecs_t when, bool* outHavePointerIds) = 0; + virtual void syncTouch(nsecs_t when, RawState* outState) = 0; private: // The current viewport. @@ -1437,6 +1536,8 @@ private: float mTiltYCenter; float mTiltYScale; + bool mExternalStylusConnected; + // Oriented motion ranges for input device info. struct OrientedRanges { InputDeviceInfo::MotionRange x; @@ -1679,9 +1780,13 @@ private: VelocityControl mWheelXVelocityControl; VelocityControl mWheelYVelocityControl; + void resetExternalStylus(); + void sync(nsecs_t when); bool consumeRawTouches(nsecs_t when, uint32_t policyFlags); + void processRawTouches(bool timeout); + void cookAndDispatch(nsecs_t when); void dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, int32_t keyEventAction, int32_t keyEventFlags); @@ -1709,6 +1814,10 @@ private: bool down, bool hovering); void abortPointerSimple(nsecs_t when, uint32_t policyFlags); + bool assignExternalStylusId(const RawState& state, bool timeout); + void applyExternalStylusButtonState(nsecs_t when); + void applyExternalStylusTouchState(nsecs_t when); + // Dispatches a motion event. // If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the // method will take care of setting the index and transmuting the action to DOWN or UP @@ -1730,7 +1839,7 @@ private: bool isPointInsideSurface(int32_t x, int32_t y); const VirtualKey* findVirtualKeyHit(int32_t x, int32_t y); - void assignPointerIds(); + static void assignPointerIds(const RawState* last, RawState* current); }; @@ -1743,7 +1852,7 @@ public: virtual void process(const RawEvent* rawEvent); protected: - virtual void syncTouch(nsecs_t when, bool* outHavePointerIds); + virtual void syncTouch(nsecs_t when, RawState* outState); virtual void configureRawPointerAxes(); virtual bool hasStylus() const; @@ -1761,7 +1870,7 @@ public: virtual void process(const RawEvent* rawEvent); protected: - virtual void syncTouch(nsecs_t when, bool* outHavePointerIds); + virtual void syncTouch(nsecs_t when, RawState* outState); virtual void configureRawPointerAxes(); virtual bool hasStylus() const; @@ -1773,6 +1882,27 @@ private: int32_t mPointerTrackingIdMap[MAX_POINTER_ID + 1]; }; +class ExternalStylusInputMapper : public InputMapper { +public: + ExternalStylusInputMapper(InputDevice* device); + virtual ~ExternalStylusInputMapper() = default; + + virtual uint32_t getSources(); + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(String8& dump); + virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + virtual void reset(nsecs_t when); + virtual void process(const RawEvent* rawEvent); + virtual void sync(nsecs_t when); + +private: + SingleTouchMotionAccumulator mSingleTouchMotionAccumulator; + RawAbsoluteAxisInfo mRawPressureAxis; + TouchButtonAccumulator mTouchButtonAccumulator; + + StylusState mStylusState; +}; + class JoystickInputMapper : public InputMapper { public: diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 40f51b6..f34b810 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -777,6 +777,14 @@ private: virtual int32_t bumpGeneration() { return ++mGeneration; } + + virtual void getExternalStylusDevices(Vector& outDevices) { + + } + + virtual void dispatchExternalStylusState(const StylusState&) { + + } }; -- cgit v1.1