Android 7.1 触摸事件代码跟踪
平台
rk3288 + Android 7.1
Framework-service
|-- frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
public InputManagerService(Context context) { this.mContext = context; this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper()); mUseDevInputEventForAudioJack = context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack); Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack=" + mUseDevInputEventForAudioJack); mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue()); String doubleTouchGestureEnablePath = context.getResources().getString( R.string.config_doubleTouchGestureEnableFile); mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null : new File(doubleTouchGestureEnablePath); LocalServices.addService(InputManagerInternal.class, new LocalService()); } public void start() { Slog.i(TAG, "Starting input manager"); nativeStart(mPtr); // Add ourself to the Watchdog monitors. Watchdog.getInstance().addMonitor(this); registerPointerSpeedSettingObserver(); registerShowTouchesSettingObserver(); registerAccessibilityLargePointerSettingObserver(); mContext.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { updatePointerSpeedFromSettings(); updateShowTouchesFromSettings(); updateAccessibilityLargePointerFromSettings(); } }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler); updatePointerSpeedFromSettings(); updateShowTouchesFromSettings(); updateAccessibilityLargePointerFromSettings(); }
Framework-jni
|-- frameworks/base/services/core/jni/Android.mk
LOCAL_SHARED_LIBRARIES += \ libandroid_runtime \ libandroidfw \ libbinder \ libcutils \ liblog \ libhardware \ libhardware_legacy \ libkeystore_binder \ libnativehelper \ libutils \ libui \ libinput \ libinputflinger \ libinputservice \ libsensorservice \ libskia \ libgui \ libusbhost \ libsuspend \ libEGL \ libGLESv2 \ libnetutils \ libdrm \ libsync \
|-- frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
#include <inputflinger/InputManager.h> static jlong nativeInit(JNIEnv* env, jclass /* clazz */, jobject serviceObj, jobject contextObj, jobject messageQueueObj) { sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); if (messageQueue == NULL) { jniThrowRuntimeException(env, "MessageQueue is not initialized."); return 0; } NativeInputManager* im = new NativeInputManager(contextObj, serviceObj, messageQueue->getLooper()); im->incStrong(0); return reinterpret_cast<jlong>(im); } static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); status_t result = im->getInputManager()->start(); if (result) { jniThrowRuntimeException(env, "Input manager could not be started."); } } NativeInputManager::NativeInputManager(jobject contextObj, jobject serviceObj, const sp<Looper>& looper) : mLooper(looper), mInteractive(true) { JNIEnv* env = jniEnv(); mContextObj = env->NewGlobalRef(contextObj); mServiceObj = env->NewGlobalRef(serviceObj); { AutoMutex _l(mLock); mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE; mLocked.pointerSpeed = 0; mLocked.pointerGesturesEnabled = true; mLocked.showTouches = false; mLocked.hardwareRotation = 0; char property[PROPERTY_VALUE_MAX]; if (property_get("ro.sf.hwrotation", property, "0") > 0) { mLocked.hardwareRotation = atoi(property) / 90; } } mInteractive = true; sp<EventHub> eventHub = new EventHub(); mInputManager = new InputManager(eventHub, this, this); }
Framework-libinputflinger
|-- frameworks/native/services/inputflinger/InputManager.cpp
InputManager::InputManager( const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& readerPolicy, const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) { mDispatcher = new InputDispatcher(dispatcherPolicy); mReader = new InputReader(eventHub, readerPolicy, mDispatcher); initialize(); } InputManager::InputManager( const sp<InputReaderInterface>& reader, const sp<InputDispatcherInterface>& dispatcher) : mReader(reader), mDispatcher(dispatcher) { initialize(); } void InputManager::initialize() { mReaderThread = new InputReaderThread(mReader); mDispatcherThread = new InputDispatcherThread(mDispatcher); } status_t InputManager::start() { status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY); if (result) { ALOGE("Could not start InputDispatcher thread due to error %d.", result); return result; } result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY); if (result) { ALOGE("Could not start InputReader thread due to error %d.", result); mDispatcherThread->requestExit(); return result; } return OK; } status_t InputManager::stop() { status_t result = mReaderThread->requestExitAndWait(); if (result) { ALOGW("Could not stop InputReader thread due to error %d.", result); } result = mDispatcherThread->requestExitAndWait(); if (result) { ALOGW("Could not stop InputDispatcher thread due to error %d.", result); } return OK; }
|-- frameworks/native/services/inputflinger/InputReader.cpp
bool InputReaderThread::threadLoop() { mReader->loopOnce(); return true; } void InputReader::loopOnce() { int32_t oldGeneration; int32_t timeoutMillis; bool inputDevicesChanged = false; Vector<InputDeviceInfo> inputDevices; { // acquire lock AutoMutex _l(mLock); oldGeneration = mGeneration; timeoutMillis = -1; uint32_t changes = mConfigurationChangesToRefresh; if (changes) { mConfigurationChangesToRefresh = 0; timeoutMillis = 0; refreshConfigurationLocked(changes); } else if (mNextTimeout != LLONG_MAX) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout); } } // release lock size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); { // acquire lock AutoMutex _l(mLock); mReaderIsAliveCondition.broadcast(); if (count) { processEventsLocked(mEventBuffer, count); } if (mNextTimeout != LLONG_MAX) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); if (now >= mNextTimeout) { #if DEBUG_RAW_EVENTS ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f); #endif mNextTimeout = LLONG_MAX; timeoutExpiredLocked(now); } } if (oldGeneration != mGeneration) { inputDevicesChanged = true; getInputDevicesLocked(inputDevices); } } // release lock // Send out a message that the describes the changed input devices. if (inputDevicesChanged) { mPolicy->notifyInputDevicesChanged(inputDevices); } // Flush queued events out to the listener. // This must happen outside of the lock because the listener could potentially call // back into the InputReader's methods, such as getScanCodeState, or become blocked // on another thread similarly waiting to acquire the InputReader lock thereby // resulting in a deadlock. This situation is actually quite plausible because the // listener is actually the input dispatcher, which calls into the window manager, // which occasionally calls into the input reader. mQueuedListener->flush(); } void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { for (const RawEvent* rawEvent = rawEvents; count;) { int32_t type = rawEvent->type; size_t batchSize = 1; if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) { int32_t deviceId = rawEvent->deviceId; while (batchSize < count) { if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT || rawEvent[batchSize].deviceId != deviceId) { break; } batchSize += 1; } #if DEBUG_RAW_EVENTS ALOGD("BatchSize: %d Count: %d", batchSize, count); #endif processEventsForDeviceLocked(deviceId, rawEvent, batchSize); } else { switch (rawEvent->type) { case EventHubInterface::DEVICE_ADDED: addDeviceLocked(rawEvent->when, rawEvent->deviceId); break; case EventHubInterface::DEVICE_REMOVED: removeDeviceLocked(rawEvent->when, rawEvent->deviceId); break; case EventHubInterface::FINISHED_DEVICE_SCAN: handleConfigurationChangedLocked(rawEvent->when); break; default: ALOG_ASSERT(false); // can't happen break; } } count -= batchSize; rawEvent += batchSize; } } void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count) { ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex < 0) { ALOGW("Discarding event for unknown deviceId %d.", deviceId); return; } InputDevice* device = mDevices.valueAt(deviceIndex); if (device->isIgnored()) { //ALOGD("Discarding event for ignored deviceId %d.", deviceId); return; } device->process(rawEvents, count); } void MultiTouchInputMapper::process(const RawEvent* rawEvent) { ALOGD("ALog MultiTouchInputMapper::process"); TouchInputMapper::process(rawEvent); mMultiTouchMotionAccumulator.process(rawEvent); } void TouchInputMapper::process(const RawEvent* rawEvent) { mCursorButtonAccumulator.process(rawEvent); mCursorScrollAccumulator.process(rawEvent); mTouchButtonAccumulator.process(rawEvent); if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { sync(rawEvent->when); } } 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. next->buttonState = mTouchButtonAccumulator.getButtonState() | mCursorButtonAccumulator.getButtonState(); // Sync scroll next->rawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); next->rawHScroll = mCursorScrollAccumulator.getRelativeHWheel(); mCursorScrollAccumulator.finishSync(); // Sync touch syncTouch(when, next); // Assign pointer ids. if (!mHavePointerIds) { assignPointerIds(last, next); } //#if DEBUG_RAW_EVENTS ALOGD("ALog 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 processRawTouches(false /*timeout*/); } void TouchInputMapper::processRawTouches(bool timeout) { if (mDeviceMode == DEVICE_MODE_DISABLED) { // Drop all input if the device is disabled. mCurrentRawState.clear(); mRawStatesPending.clear(); return; } // 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; } // All ready to go. clearStylusDataPendingFlags(); mCurrentRawState.copyFrom(next); if (mCurrentRawState.when < mLastRawState.when) { mCurrentRawState.when = mLastRawState.when; } cookAndDispatch(mCurrentRawState.when); } if (count != 0) { mRawStatesPending.removeItemsAt(0, count); } if (mExternalStylusDataPending) { if (timeout) { nsecs_t when = mExternalStylusFusionTimeout - STYLUS_DATA_LATENCY; clearStylusDataPendingFlags(); mCurrentRawState.copyFrom(mLastRawState); #if DEBUG_STYLUS_FUSION ALOGD("Timeout expired, synthesizing event with new stylus data"); #endif cookAndDispatch(when); } else if (mExternalStylusFusionTimeout == LLONG_MAX) { mExternalStylusFusionTimeout = mExternalStylusState.when + TOUCH_DATA_TIMEOUT; getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout); } } } 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(); } if (mParameters.wake) { policyFlags |= POLICY_FLAG_WAKE; } } // 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, mLastCookedState.buttonState, mCurrentCookedState.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(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 (!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(mCurrentRawState.buttonState); mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, mCurrentCookedState.cookedPointerData.touchingIdBits); } if (!mCurrentMotionAborted) { dispatchButtonRelease(when, policyFlags); dispatchHoverExit(when, policyFlags); dispatchTouches(when, policyFlags); dispatchHoverEnterAndMove(when, policyFlags); dispatchButtonPress(when, policyFlags); } if (mCurrentCookedState.cookedPointerData.pointerCount == 0) { mCurrentMotionAborted = false; } } // Synthesize key up from raw buttons if needed. synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, policyFlags, mLastCookedState.buttonState, mCurrentCookedState.buttonState); // Clear some transient state. 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::dispatchTouches(nsecs_t when, uint32_t policyFlags) { BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits; BitSet32 lastIdBits = mLastCookedState.cookedPointerData.touchingIdBits; int32_t metaState = getContext()->getGlobalMetaState(); int32_t buttonState = mCurrentCookedState.buttonState; if (currentIdBits == lastIdBits) { if (!currentIdBits.isEmpty()) { // No pointer id changes so this is a move event. // The listener takes care of batching moves so we don't have to deal with that here. dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } } else { // There may be pointers going up and pointers going down and pointers moving // all at the same time. BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value); BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value); BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value); BitSet32 dispatchedIdBits(lastIdBits.value); // 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( mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, mLastCookedState.cookedPointerData.pointerProperties, mLastCookedState.cookedPointerData.pointerCoords, mLastCookedState.cookedPointerData.idToIndex, moveIdBits); if (buttonState != mLastCookedState.buttonState) { moveNeeded = true; } // Dispatch pointer up events. while (!upIdBits.isEmpty()) { uint32_t upId = upIdBits.clearFirstMarkedBit(); dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, 0, mLastCookedState.cookedPointerData.pointerProperties, mLastCookedState.cookedPointerData.pointerCoords, mLastCookedState.cookedPointerData.idToIndex, dispatchedIdBits, upId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); dispatchedIdBits.clearBit(upId); } // Dispatch move events if any of the remaining pointers moved from their old locations. // Although applications receive new locations as part of individual pointer up // events, they do not generally handle them except when presented in a move event. if (moveNeeded && !moveIdBits.isEmpty()) { ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value); dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, 0, mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } // Dispatch pointer down events using the new pointer locations. while (!downIdBits.isEmpty()) { uint32_t downId = downIdBits.clearFirstMarkedBit(); dispatchedIdBits.markBit(downId); if (dispatchedIdBits.count() == 1) { // First pointer is going down. Set down time. mDownTime = when; } dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0, mCurrentCookedState.cookedPointerData.pointerProperties, mCurrentCookedState.cookedPointerData.pointerCoords, mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits, downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } } } void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, int32_t action, int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, const PointerProperties* properties, const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) { //AnsonCode ALOGD("ALog dispatchMotion source(%d), width(%d), height(%d), orientation(%d)", source, mSurfaceWidth, mSurfaceHeight, mSurfaceOrientation); ALOGD("ALog coords(%f, %f), xP(%f), yP(%f)", coords->getX(), coords->getY(), xPrecision, yPrecision); PointerCoords pointerCoords[MAX_POINTERS]; PointerProperties pointerProperties[MAX_POINTERS]; uint32_t pointerCount = 0; while (!idBits.isEmpty()) { uint32_t id = idBits.clearFirstMarkedBit(); uint32_t index = idToIndex[id]; pointerProperties[pointerCount].copyFrom(properties[index]); pointerCoords[pointerCount].copyFrom(coords[index]); if (changedId >= 0 && id == uint32_t(changedId)) { action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; } pointerCount += 1; } ALOG_ASSERT(pointerCount != 0); if (changedId >= 0 && pointerCount == 1) { // Replace initial down and final up action. // We can compare the action without masking off the changed pointer index // because we know the index is 0. if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) { action = AMOTION_EVENT_ACTION_DOWN; } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) { action = AMOTION_EVENT_ACTION_UP; } else { // Can't happen. ALOG_ASSERT(false); } } NotifyMotionArgs args(when, getDeviceId(), source, policyFlags, action, actionButton, flags, metaState, buttonState, edgeFlags, mViewport.displayId, pointerCount, pointerProperties, pointerCoords, xPrecision, yPrecision, downTime); getListener()->notifyMotion(&args); } //补充: 此函数对数据进行二次转换, 与屏幕方向等因素有关 void TouchInputMapper::cookPointerData() { ALOGD("ALog cookPointerData"); uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount; mCurrentCookedState.cookedPointerData.clear(); mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount; mCurrentCookedState.cookedPointerData.hoveringIdBits = mCurrentRawState.rawPointerData.hoveringIdBits; mCurrentCookedState.cookedPointerData.touchingIdBits = mCurrentRawState.rawPointerData.touchingIdBits; if (mCurrentCookedState.cookedPointerData.pointerCount == 0) { mCurrentCookedState.buttonState = 0; } else { mCurrentCookedState.buttonState = mCurrentRawState.buttonState; } // 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 = mCurrentRawState.rawPointerData.pointers[i]; // Size float touchMajor, touchMinor, toolMajor, toolMinor, size; switch (mCalibration.sizeCalibration) { case Calibration::SIZE_CALIBRATION_GEOMETRIC: case Calibration::SIZE_CALIBRATION_DIAMETER: case Calibration::SIZE_CALIBRATION_BOX: case Calibration::SIZE_CALIBRATION_AREA: if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.toolMajor.valid) { touchMajor = in.touchMajor; touchMinor = mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor; toolMajor = in.toolMajor; toolMinor = mRawPointerAxes.toolMinor.valid ? in.toolMinor : in.toolMajor; size = mRawPointerAxes.touchMinor.valid ? avg(in.touchMajor, in.touchMinor) : in.touchMajor; } else if (mRawPointerAxes.touchMajor.valid) { toolMajor = touchMajor = in.touchMajor; toolMinor = touchMinor = mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor; size = mRawPointerAxes.touchMinor.valid ? avg(in.touchMajor, in.touchMinor) : in.touchMajor; } else if (mRawPointerAxes.toolMajor.valid) { touchMajor = toolMajor = in.toolMajor; touchMinor = toolMinor = mRawPointerAxes.toolMinor.valid ? in.toolMinor : in.toolMajor; size = mRawPointerAxes.toolMinor.valid ? avg(in.toolMajor, in.toolMinor) : in.toolMajor; } else { ALOG_ASSERT(false, "No touch or tool axes. " "Size calibration should have been resolved to NONE."); touchMajor = 0; touchMinor = 0; toolMajor = 0; toolMinor = 0; size = 0; } if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) { uint32_t touchingCount = mCurrentRawState.rawPointerData.touchingIdBits.count(); if (touchingCount > 1) { touchMajor /= touchingCount; touchMinor /= touchingCount; toolMajor /= touchingCount; toolMinor /= touchingCount; size /= touchingCount; } } if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_GEOMETRIC) { touchMajor *= mGeometricScale; touchMinor *= mGeometricScale; toolMajor *= mGeometricScale; toolMinor *= mGeometricScale; } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_AREA) { touchMajor = touchMajor > 0 ? sqrtf(touchMajor) : 0; touchMinor = touchMajor; toolMajor = toolMajor > 0 ? sqrtf(toolMajor) : 0; toolMinor = toolMajor; } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DIAMETER) { touchMinor = touchMajor; toolMinor = toolMajor; } mCalibration.applySizeScaleAndBias(&touchMajor); mCalibration.applySizeScaleAndBias(&touchMinor); mCalibration.applySizeScaleAndBias(&toolMajor); mCalibration.applySizeScaleAndBias(&toolMinor); size *= mSizeScale; break; default: touchMajor = 0; touchMinor = 0; toolMajor = 0; toolMinor = 0; size = 0; break; } // Pressure float pressure; switch (mCalibration.pressureCalibration) { case Calibration::PRESSURE_CALIBRATION_PHYSICAL: case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: pressure = in.pressure * mPressureScale; break; default: pressure = in.isHovering ? 0 : 1; break; } // Tilt and Orientation float tilt; float orientation; if (mHaveTilt) { float tiltXAngle = (in.tiltX - mTiltXCenter) * mTiltXScale; float tiltYAngle = (in.tiltY - mTiltYCenter) * mTiltYScale; orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle)); tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle)); } else { tilt = 0; switch (mCalibration.orientationCalibration) { case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: orientation = in.orientation * mOrientationScale; break; case Calibration::ORIENTATION_CALIBRATION_VECTOR: { int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4); int32_t c2 = signExtendNybble(in.orientation & 0x0f); if (c1 != 0 || c2 != 0) { orientation = atan2f(c1, c2) * 0.5f; float confidence = hypotf(c1, c2); float scale = 1.0f + confidence / 16.0f; touchMajor *= scale; touchMinor /= scale; toolMajor *= scale; toolMinor /= scale; } else { orientation = 0; } break; } default: orientation = 0; } } // Distance float distance; switch (mCalibration.distanceCalibration) { case Calibration::DISTANCE_CALIBRATION_SCALED: distance = in.distance * mDistanceScale; break; default: distance = 0; } // Coverage int32_t rawLeft, rawTop, rawRight, rawBottom; switch (mCalibration.coverageCalibration) { case Calibration::COVERAGE_CALIBRATION_BOX: rawLeft = (in.toolMinor & 0xffff0000) >> 16; rawRight = in.toolMinor & 0x0000ffff; rawBottom = in.toolMajor & 0x0000ffff; rawTop = (in.toolMajor & 0xffff0000) >> 16; break; default: rawLeft = rawTop = rawRight = rawBottom = 0; break; } // Adjust X,Y coords for device calibration // TODO: Adjust coverage coords? float xTransformed = in.x, yTransformed = in.y; mAffineTransform.applyTo(xTransformed, yTransformed); // Adjust X, Y, and coverage coords for surface orientation. float x, y; float left, top, right, bottom; /*ALOGD("ALog deviceName %s", getDeviceName().string()); //AnsonCode rotation int rot = DISPLAY_ORIENTATION_0; if(mSurfaceOrientation == DISPLAY_ORIENTATION_180)rot = DISPLAY_ORIENTATION_0; else if(mSurfaceOrientation == DISPLAY_ORIENTATION_0)rot = DISPLAY_ORIENTATION_180;*/ switch (mSurfaceOrientation) { case DISPLAY_ORIENTATION_90: x = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; y = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale + mXTranslate; left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; right = float(rawBottom- mRawPointerAxes.y.minValue) * mYScale + mYTranslate; bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate; top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate; orientation -= M_PI_2; if (mOrientedRanges.haveOrientation && orientation < mOrientedRanges.orientation.min) { orientation += (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); } break; case DISPLAY_ORIENTATION_180: x = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale + mXTranslate; y = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale + mYTranslate; left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate; right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate; bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate; top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate; orientation -= M_PI; if (mOrientedRanges.haveOrientation && orientation < mOrientedRanges.orientation.min) { orientation += (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); } break; case DISPLAY_ORIENTATION_270: x = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale + mYTranslate; y = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate; right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate; bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; orientation += M_PI_2; if (mOrientedRanges.haveOrientation && orientation > mOrientedRanges.orientation.max) { orientation -= (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); } break; default: x = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; y = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; break; } // Write output coords. PointerCoords& out = mCurrentCookedState.cookedPointerData.pointerCoords[i]; out.clear(); out.setAxisValue(AMOTION_EVENT_AXIS_X, x); out.setAxisValue(AMOTION_EVENT_AXIS_Y, y); out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size); out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor); out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor); out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation); out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt); out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance); if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) { out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_1, left); out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_2, top); out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_3, right); out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_4, bottom); } else { out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor); out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor); } // Write output properties. PointerProperties& properties = mCurrentCookedState.cookedPointerData.pointerProperties[i]; uint32_t id = in.id; properties.clear(); properties.id = id; properties.toolType = in.toolType; // Write id index. mCurrentCookedState.cookedPointerData.idToIndex[id] = i; } }