在上一篇中,当action == MotionEvent.ACTION_MOVE,设置自定义的action给自己的应用接受。
但别的应用也可能会处理MotionEvent.ACTION_MOVE事件,从而导致有别的问题出现。
所以,自定义一个action事件,MotionEvent.ACTION_HOVER_MOVE。
在InputReader.cpp中修改鼠标事件
InputReader.cpp
void MouseInputMapper::sync(nsecs_t when) {
uint32_t fields = mAccumulator.fields;
if (fields == 0) {
return; // no new state changes, so nothing to do
}
int motionEventAction;
PointerCoords pointerCoords;
nsecs_t downTime;
{ // acquire lock
AutoMutex _l(mLock);
bool downChanged = fields & Accumulator::FIELD_BTN_MOUSE;
if (downChanged) {
if (mAccumulator.btnMouse) {
mLocked.down = true;
mLocked.downTime = when;
} else {
mLocked.down = false;
}
motionEventAction = mLocked.down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
} else if (mLocked.down) {
motionEventAction = AMOTION_EVENT_ACTION_MOVE;
} else {
motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE;
}
.....
}
InputDispatcher.cpp中增加对hover_move事件的处理
void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t source,
uint32_t policyFlags, int32_t action, int32_t flags, int32_t metaState, int32_t edgeFlags,
uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime) {
......
bool needWake;
{ // acquire lock
AutoMutex _l(mLock);
if (action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
for (EventEntry* entry = mInboundQueue.tailSentinel.prev;
entry != & mInboundQueue.headSentinel; entry = entry->prev) {
if (entry->type != EventEntry::TYPE_MOTION) {
// Keep looking for motion events.
continue;
}
MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
if (motionEntry->deviceId != deviceId) {
// Keep looking for this device.
continue;
}
if (motionEntry->action != AMOTION_EVENT_ACTION_HOVER_MOVE
|| motionEntry->pointerCount != pointerCount
|| motionEntry->isInjected()) {
// Last motion event in the queue for this device is not compatible for
// appending new samples. Stop here.
goto NoBatchingOrStreaming2;
}
// The last motion event is a move and is compatible for appending.
// Do the batching magic.
mAllocator.appendMotionSample(motionEntry, eventTime, pointerCoords);
#if DEBUG_BATCHING
LOGD("Appended motion sample onto batch for most recent "
"hover motion event for this device in the inbound queue.");
#endif
return; // done!
}
if (mCurrentInputTargetsValid) {
for (size_t i = 0; i < mCurrentInputTargets.size(); i++) {
const InputTarget& inputTarget = mCurrentInputTargets[i];
if ((inputTarget.flags & InputTarget::FLAG_FOREGROUND) == 0) {
// Skip non-foreground targets. We only want to stream if there is at
// least one foreground target whose dispatch is still in progress.
continue;
}
ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
if (connectionIndex < 0) {
// Connection must no longer be valid.
continue;
}
sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
if (connection->outboundQueue.isEmpty()) {
// This foreground target has an empty outbound queue.
continue;
}
DispatchEntry* dispatchEntry = connection->outboundQueue.headSentinel.next;
if (! dispatchEntry->inProgress
|| dispatchEntry->eventEntry->type != EventEntry::TYPE_MOTION
|| dispatchEntry->isSplit()) {
// No motion event is being dispatched, or it is being split across
// windows in which case we cannot stream.
continue;
}
MotionEntry* motionEntry = static_cast<MotionEntry*>(
dispatchEntry->eventEntry);
if (motionEntry->action != AMOTION_EVENT_ACTION_HOVER_MOVE
|| motionEntry->deviceId != deviceId
|| motionEntry->pointerCount != pointerCount
|| motionEntry->isInjected()) {
// The motion event is not compatible with this move.
continue;
}
// Hurray! This foreground target is currently dispatching a move event
// that we can stream onto. Append the motion sample and resume dispatch.
mAllocator.appendMotionSample(motionEntry, eventTime, pointerCoords);
#if DEBUG_BATCHING
LOGD("Appended motion sample onto batch for most recently dispatched "
"hover motion event for this device in the outbound queues. "
"Attempting to stream the motion sample.");
#endif
nsecs_t currentTime = now();
dispatchEventToCurrentInputTargetsLocked(currentTime, motionEntry,
true /*resumeWithAppendedMotionSample*/);
runCommandsLockedInterruptible();
return; // done!
}
}
NoBatchingOrStreaming2:;
}
// Attempt batching and streaming of move events.
if (action == AMOTION_EVENT_ACTION_MOVE) {
......
}
}
InputTransport.cpp
status_t InputPublisher::publishMotionEvent(
....
// Cache essential information about the motion event to ensure that a malicious consumer
// cannot confuse the publisher by modifying the contents of the shared memory buffer while
// it is being updated.
if (action == AMOTION_EVENT_ACTION_MOVE || action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
mMotionEventPointerCount = pointerCount;
mMotionEventSampleDataStride = InputMessage::sampleDataStride(pointerCount);
mMotionEventSampleDataTail = InputMessage::sampleDataPtrIncrement(
mSharedMessage->motion.sampleData, mMotionEventSampleDataStride);
} else {
mMotionEventSampleDataTail = NULL;
}
return OK;
}
ViewRoot 中,修改不变。当ViewGroup分发事件时,在View中屏蔽自定义的action。
public boolean dispatchTouchEvent(MotionEvent event) {
if (!onFilterTouchEventForSecurity(event)) {
return false;
}
// Not handled the event, the subView will handle it.
if (event.getAction() == MotionEvent.ACTION_HOVER_MOVE) {
return true;
}
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}
这样,子View只能重写此方法,来得到我们的action。
public class UButton extends ImageView {
private OnTouchListener mOnTouchListener;
public UButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setOnTouchListener(OnTouchListener l) {
mOnTouchListener = l;
}
public boolean dispatchTouchEvent(MotionEvent event) {
if (!onFilterTouchEventForSecurity(event)) {
return false;
}
if (mOnTouchListener != null && mOnTouchListener.onTouch(this, event)) {
return true;
}
return super.onTouchEvent(event);
}
}
消息获取流程附图