基于Android 7.0源碼分析
應(yīng)用收到Motion事件傳遞至Activity的過程
應(yīng)用對于Motion事件的處理比較復(fù)雜席覆,不同類型的事件處理方式不同:
- Down事件 直接處理
- Move事件 對于大多數(shù)Move事件囊咏,結(jié)合繪制過程處理陕见,當(dāng)應(yīng)用收到Vsync時煌集,處理一批Move事件(Move事件之間的間隔通常小于16ms)
- Up事件 直接處理
直接處理事件的流程(Down事件為例)
下面從應(yīng)用UI線程的Looper
開始分析
int Looper::pollInner(int timeoutMillis) {
......
// 從此喚醒
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
......
for (int i = 0; i < eventCount; i++) {
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
if (fd == mWakeEventFd) {
if (epollEvents & EPOLLIN) {
awoken();
} else {
ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);
}
} else {
ssize_t requestIndex = mRequests.indexOfKey(fd);
if (requestIndex >= 0) {
int events = 0;
if (epollEvents & EPOLLIN) events |= EVENT_INPUT;
if (epollEvents & EPOLLOUT) events |= EVENT_OUTPUT;
if (epollEvents & EPOLLERR) events |= EVENT_ERROR;
if (epollEvents & EPOLLHUP) events |= EVENT_HANGUP;
// 找到InputChannel的fd對應(yīng)的Request,封裝成Response
// Request在應(yīng)用啟動注冊InputChannel時添加
pushResponse(events, mRequests.valueAt(requestIndex));
} else {
ALOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
"no longer registered.", epollEvents, fd);
}
}
}
......
// Invoke all response callbacks.
for (size_t i = 0; i < mResponses.size(); i++) {
Response& response = mResponses.editItemAt(i);
if (response.request.ident == POLL_CALLBACK) {
int fd = response.request.fd;
int events = response.events;
void* data = response.request.data;
#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
ALOGD("%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p",
this, response.request.callback.get(), fd, events, data);
#endif
// Invoke the callback. Note that the file descriptor may be closed by
// the callback (and potentially even reused) before the function returns so
// we need to be a little careful when removing the file descriptor afterwards.
// 調(diào)用回調(diào)的handleEvent方法哥倔,這里callback為NativeInputEventReceiver
int callbackResult = response.request.callback->handleEvent(fd, events, data);
if (callbackResult == 0) {
removeFd(fd, response.request.seq);
}
// Clear the callback reference in the response structure promptly because we
// will not clear the response vector itself until the next poll.
response.request.callback.clear();
result = POLL_CALLBACK;
}
}
return result;
}
下面看NativeInputEventReceiver
的handleEvent()
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
......
if (events & ALOOPER_EVENT_INPUT) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
// 處理InputDispatcher發(fā)送的輸入事件
status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);
mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
return status == OK || status == NO_MEMORY ? 1 : 0;
}
......
}
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
// consumeBatches為false
if (consumeBatches) {
mBatchedInputEventPending = false;
}
// outConsumedBatch為NULL
if (outConsumedBatch) {
*outConsumedBatch = false;
}
ScopedLocalRef<jobject> receiverObj(env, NULL);
bool skipCallbacks = false;
for (;;) {
uint32_t seq;
InputEvent* inputEvent;
// 讀取輸入事件到inputEvent中辅搬,對于Down事件status為OK(0)
status_t status = mInputConsumer.consume(&mInputEventFactory,
consumeBatches, frameTime, &seq, &inputEvent);
......
if (!skipCallbacks) {
......
jobject inputEventObj;
switch (inputEvent->getType()) {
......
case AINPUT_EVENT_TYPE_MOTION: {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Received motion event.", getInputChannelName());
}
MotionEvent* motionEvent = static_cast<MotionEvent*>(inputEvent);
if ((motionEvent->getAction() & AMOTION_EVENT_ACTION_MOVE) && outConsumedBatch) {
*outConsumedBatch = true;
}
// 創(chuàng)建Java層的MotionEvent對象及其對應(yīng)的Native層的MotionEvent對象,返回JNI本地引用
inputEventObj = android_view_MotionEvent_obtainAsCopy(env, motionEvent);
break;
}
......
}
if (inputEventObj) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName());
}
// 調(diào)用Java層WindowInputEventReceiver(繼承自InputEventReceiver)的dispatchInputEvent方法
env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
if (env->ExceptionCheck()) {
ALOGE("Exception dispatching input event.");
skipCallbacks = true;
}
env->DeleteLocalRef(inputEventObj);
} else {
ALOGW("channel '%s' ~ Failed to obtain event object.", getInputChannelName());
skipCallbacks = true;
}
}
......
}
}
思考:Native線程如何才能調(diào)用Java伏尼?原理是什么忿檩?
對于InputEventReceiver
的dispatchInputEvent()
處理流程,在后文中分析爆阶。
下面看InputConsumer
的consume()
實現(xiàn)
status_t InputConsumer::consume(InputEventFactoryInterface* factory,
bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
*outSeq = 0;
*outEvent = NULL;
// Fetch the next input message.
// Loop until an event can be returned or no additional events are received.
// 循環(huán)讀取事件直到讀取到特定的事件或者沒有事件可讀
while (!*outEvent) {
if (mMsgDeferred) {
// mMsg contains a valid input message from the previous call to consume
// that has not yet been processed.
mMsgDeferred = false;
} else {
// Receive a fresh message.
// 讀取Down事件放入InputMessage中燥透,result為OK
status_t result = mChannel->receiveMessage(&mMsg);
......
}
switch (mMsg.header.type) {
......
case AINPUT_EVENT_TYPE_MOTION: {
// 查找事件所屬Batch,對于Down事件無Batch
ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source);
......
// 創(chuàng)建MotionEvent
MotionEvent* motionEvent = factory->createMotionEvent();
if (! motionEvent) return NO_MEMORY;
// 更新TouchState辨图,與Touch resample相關(guān)
updateTouchState(&mMsg);
// InputMessage初始化MotionEvent
initializeMotionEvent(motionEvent, &mMsg);
*outSeq = mMsg.body.motion.seq;
*outEvent = motionEvent;
break;
}
}
}
return OK;
}
對于Down事件等直接處理的事件兽掰,處理過程相對簡單,下面看Batch事件的處理過程徒役。
Move事件作為Batch處理的流程
Batch的第一個Move事件的處理
下面從NativeInputEventReceiver
的consumeEvents()
開始分析孽尽。
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
// consumeBatches為false
if (consumeBatches) {
mBatchedInputEventPending = false;
}
// outConsumedBatch為NULL
if (outConsumedBatch) {
*outConsumedBatch = false;
}
ScopedLocalRef<jobject> receiverObj(env, NULL);
bool skipCallbacks = false;
for (;;) {
uint32_t seq;
InputEvent* inputEvent;
// 讀取Move事件,返回status為WOULD_BLOCK
status_t status = mInputConsumer.consume(&mInputEventFactory,
consumeBatches, frameTime, &seq, &inputEvent);
if (status) {
if (status == WOULD_BLOCK) {
if (!skipCallbacks && !mBatchedInputEventPending
&& mInputConsumer.hasPendingBatch()) {
// There is a pending batch. Come back later.
if (!receiverObj.get()) {
receiverObj.reset(jniGetReferent(env, mReceiverWeakGlobal));
if (!receiverObj.get()) {
ALOGW("channel '%s' ~ Receiver object was finalized "
"without being disposed.", getInputChannelName());
return DEAD_OBJECT;
}
}
// 防止Batch的后續(xù)Move事件再次請求
mBatchedInputEventPending = true;
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Dispatching batched input event pending notification.",
getInputChannelName());
}
// 調(diào)用WindowInputEventReceiver(繼承自InputEventReceiver)的dispatchBatchedInputEventPending方法忧勿,請求Vsync到來時處理Batch事件
env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchBatchedInputEventPending);
}
return OK;
......
}
......
}
}
}
status_t InputConsumer::consume(InputEventFactoryInterface* factory,
bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
// consumeBatches為false
......
*outSeq = 0;
*outEvent = NULL;
// Fetch the next input message.
// Loop until an event can be returned or no additional events are received.
while (!*outEvent) {
if (mMsgDeferred) {
// mMsg contains a valid input message from the previous call to consume
// that has not yet been processed.
mMsgDeferred = false;
} else {
// Receive a fresh message.
// 讀取Move事件
status_t result = mChannel->receiveMessage(&mMsg);
if (result) {
// 通常第二次讀取事件,result為WOULD_BLOCK
// Consume the next batched event unless batches are being held for later.
if (consumeBatches || result != WOULD_BLOCK) {
result = consumeBatch(factory, frameTime, outSeq, outEvent);
if (*outEvent) {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u",
mChannel->getName().string(), *outSeq);
#endif
break;
}
}
// 返回WOULD_BLOCK
return result;
}
}
switch (mMsg.header.type) {
......
case AINPUT_EVENT_TYPE_MOTION: {
// 對于Batch的首個Move事件杉女,batchIndex返回-1
ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source);
......
// Start a new batch if needed.
if (mMsg.body.motion.action == AMOTION_EVENT_ACTION_MOVE
|| mMsg.body.motion.action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
// 創(chuàng)建新的Batch,Move事件添加到Batch
mBatches.push();
Batch& batch = mBatches.editTop();
batch.samples.push(mMsg);
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' consumer ~ started batch event",
mChannel->getName().string());
#endif
break;
}
......
}
......
}
}
return OK;
}
對于Batch的首個Move事件鸳吸,創(chuàng)建新的Batch熏挎,Move事件添加到Batch,然后循環(huán)讀取晌砾,通常返回WOULD_BLOCK(無事件可讀)坎拐。最終調(diào)用WindowInputEventReceiver
的dispatchBatchedInputEventPending()
。
// Called from native code.
@SuppressWarnings("unused")
private void dispatchBatchedInputEventPending() {
onBatchedInputEventPending();
}
@Override
public void onBatchedInputEventPending() {
// 通常mUnbufferedInputDispatch為false
if (mUnbufferedInputDispatch) {
super.onBatchedInputEventPending();
} else {
// 向Choreographer添加CALLBACK_INPUT類型的回調(diào)
scheduleConsumeBatchedInput();
}
}
void scheduleConsumeBatchedInput() {
if (!mConsumeBatchedInputScheduled) {
mConsumeBatchedInputScheduled = true;
// 當(dāng)Vsync到來時养匈,回調(diào)mConsumedBatchedInputRunnable
mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
mConsumedBatchedInputRunnable, null);
}
}
- Choreographer 負(fù)責(zé)接收顯示子系統(tǒng)分發(fā)的Vsync信號哼勇,協(xié)調(diào)動畫、輸入以及繪制
下面看Vsync到來之前呕乎,Batch的后續(xù)Move事件的處理积担。
Batch的后續(xù)Move事件的處理
下面仍然從NativeInputEventReceiver
的consumeEvents()
開始分析
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
......
// consumeBatches為false
if (consumeBatches) {
mBatchedInputEventPending = false;
}
// outConsumedBatch為null
if (outConsumedBatch) {
*outConsumedBatch = false;
}
ScopedLocalRef<jobject> receiverObj(env, NULL);
bool skipCallbacks = false;
for (;;) {
uint32_t seq;
InputEvent* inputEvent;
// 讀取事件
status_t status = mInputConsumer.consume(&mInputEventFactory,
consumeBatches, frameTime, &seq, &inputEvent);
// 這里status為WOULD_BLOCK
if (status) {
if (status == WOULD_BLOCK) {
// mBatchedInputEventPending在Batch的首個Move事件處理時設(shè)為true
if (!skipCallbacks && !mBatchedInputEventPending
&& mInputConsumer.hasPendingBatch()) {
// There is a pending batch. Come back later.
if (!receiverObj.get()) {
receiverObj.reset(jniGetReferent(env, mReceiverWeakGlobal));
if (!receiverObj.get()) {
ALOGW("channel '%s' ~ Receiver object was finalized "
"without being disposed.", getInputChannelName());
return DEAD_OBJECT;
}
}
mBatchedInputEventPending = true;
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Dispatching batched input event pending notification.",
getInputChannelName());
}
env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchBatchedInputEventPending);
if (env->ExceptionCheck()) {
ALOGE("Exception dispatching batched input events.");
mBatchedInputEventPending = false; // try again later
}
}
// 直接返回
return OK;
}
......
}
}
}
status_t InputConsumer::consume(InputEventFactoryInterface* factory,
bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
......
*outSeq = 0;
*outEvent = NULL;
// Fetch the next input message.
// Loop until an event can be returned or no additional events are received.
while (!*outEvent) {
if (mMsgDeferred) {
// mMsg contains a valid input message from the previous call to consume
// that has not yet been processed.
mMsgDeferred = false;
} else {
// Receive a fresh message.
// 讀取InputMessage,有事件返回OK,再次讀取往往返回WOULD_BLOCK
status_t result = mChannel->receiveMessage(&mMsg);
if (result) {
// Consume the next batched event unless batches are being held for later.
if (consumeBatches || result != WOULD_BLOCK) {
result = consumeBatch(factory, frameTime, outSeq, outEvent);
if (*outEvent) {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u",
mChannel->getName().string(), *outSeq);
#endif
break;
}
}
return result;
}
}
switch (mMsg.header.type) {
......
case AINPUT_EVENT_TYPE_MOTION: {
// 查找Move事件所屬的Batch
ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source);
if (batchIndex >= 0) {
// 添加后續(xù)Move事件到Batch
Batch& batch = mBatches.editItemAt(batchIndex);
if (canAddSample(batch, &mMsg)) {
batch.samples.push(mMsg);
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' consumer ~ appended to batch event",
mChannel->getName().string());
#endif
// while循環(huán)繼續(xù)讀取
break;
} else {
// We cannot append to the batch in progress, so we need to consume
// the previous batch right now and defer the new message until later.
mMsgDeferred = true;
// 通常猬仁,當(dāng)Up事件到來時帝璧,不能添加到Batch先誉,如果有先前的Batch事件,立即處理
status_t result = consumeSamples(factory,
batch, batch.samples.size(), outSeq, outEvent);
mBatches.removeAt(batchIndex);
if (result) {
return result;
}
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' consumer ~ consumed batch event and "
"deferred current event, seq=%u",
mChannel->getName().string(), *outSeq);
#endif
break;
}
}
......
}
......
}
}
}
Batch的后續(xù)Move事件的處理相對簡單的烁,只是將Move事件添加到Batch,下面分析Vsync信號到來后褐耳,Batch事件的處理。
收到Vsync后處理Batch Move事件
下面從App收到Vsync信號調(diào)用CALLBACK_INPUT
類型的回調(diào)ConsumeBatchedInputRunnable
開始分析渴庆。
final class ConsumeBatchedInputRunnable implements Runnable {
@Override
public void run() {
// 處理Batch事件
doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
}
}
void doConsumeBatchedInput(long frameTimeNanos) {
if (mConsumeBatchedInputScheduled) {
mConsumeBatchedInputScheduled = false;
if (mInputEventReceiver != null) {
// 調(diào)用WindowInputEventReceiver的consumeBatchedInputEvents處理事件
if (mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos)
&& frameTimeNanos != -1) {
// If we consumed a batch here, we want to go ahead and schedule the
// consumption of batched input events on the next frame. Otherwise, we would
// wait until we have more input events pending and might get starved by other
// things occurring in the process. If the frame time is -1, however, then
// we're in a non-batching mode, so there's no need to schedule this.
// 請求繪制下一幀時處理Batch事件
scheduleConsumeBatchedInput();
}
}
// 處理事件
doProcessInputEvents();
}
}
public final boolean consumeBatchedInputEvents(long frameTimeNanos) {
if (mReceiverPtr == 0) {
Log.w(TAG, "Attempted to consume batched input events but the input event "
+ "receiver has already been disposed.");
} else {
// mReceiverPtr為NativeInputEventReceiver的地址
return nativeConsumeBatchedInputEvents(mReceiverPtr, frameTimeNanos);
}
return false;
}
static jboolean nativeConsumeBatchedInputEvents(JNIEnv* env, jclass clazz, jlong receiverPtr,
jlong frameTimeNanos) {
sp<NativeInputEventReceiver> receiver =
reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
bool consumedBatch;
// 調(diào)用NativeInputEventReceiver的consumeEvents方法
// 這里參數(shù)consumeBatches為true, frameTimeNanos不為-1
status_t status = receiver->consumeEvents(env, true /*consumeBatches*/, frameTimeNanos,
&consumedBatch);
if (status && status != DEAD_OBJECT && !env->ExceptionCheck()) {
String8 message;
message.appendFormat("Failed to consume batched input event. status=%d", status);
jniThrowRuntimeException(env, message.string());
return JNI_FALSE;
}
return consumedBatch ? JNI_TRUE : JNI_FALSE;
}
下面看consumeEvents()
的處理
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
// consumeBatches為true
if (consumeBatches) {
mBatchedInputEventPending = false;
}
// outConsumedBatch不為NULL
if (outConsumedBatch) {
*outConsumedBatch = false;
}
ScopedLocalRef<jobject> receiverObj(env, NULL);
bool skipCallbacks = false;
for (;;) {
uint32_t seq;
InputEvent* inputEvent;
// 讀取Batch事件放入inputEvent中漱病,這里status通常返回OK
status_t status = mInputConsumer.consume(&mInputEventFactory,
consumeBatches, frameTime, &seq, &inputEvent);
......
if (!skipCallbacks) {
if (!receiverObj.get()) {
receiverObj.reset(jniGetReferent(env, mReceiverWeakGlobal));
if (!receiverObj.get()) {
ALOGW("channel '%s' ~ Receiver object was finalized "
"without being disposed.", getInputChannelName());
return DEAD_OBJECT;
}
}
jobject inputEventObj;
switch (inputEvent->getType()) {
......
case AINPUT_EVENT_TYPE_MOTION: {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Received motion event.", getInputChannelName());
}
MotionEvent* motionEvent = static_cast<MotionEvent*>(inputEvent);
// 處理Batch Move事件
if ((motionEvent->getAction() & AMOTION_EVENT_ACTION_MOVE) && outConsumedBatch) {
*outConsumedBatch = true;
}
inputEventObj = android_view_MotionEvent_obtainAsCopy(env, motionEvent);
break;
}
......
}
if (inputEventObj) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName());
}
// 調(diào)用InputEventReceiver的dispatchInputEvent方法處理
env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
if (env->ExceptionCheck()) {
ALOGE("Exception dispatching input event.");
skipCallbacks = true;
}
env->DeleteLocalRef(inputEventObj);
} else {
ALOGW("channel '%s' ~ Failed to obtain event object.", getInputChannelName());
skipCallbacks = true;
}
}
......
}
}
status_t InputConsumer::consume(InputEventFactoryInterface* factory,
bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
......
*outSeq = 0;
*outEvent = NULL;
// Fetch the next input message.
// Loop until an event can be returned or no additional events are received.
while (!*outEvent) {
if (mMsgDeferred) {
// mMsg contains a valid input message from the previous call to consume
// that has not yet been processed.
mMsgDeferred = false;
} else {
// Receive a fresh message.
// 讀取消息,這里通常返回WOULD_BLOCK
status_t result = mChannel->receiveMessage(&mMsg);
if (result) {
// Consume the next batched event unless batches are being held for later.
// consumeBatches為true把曼,處理Batch事件
if (consumeBatches || result != WOULD_BLOCK) {
result = consumeBatch(factory, frameTime, outSeq, outEvent);
if (*outEvent) {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u",
mChannel->getName().string(), *outSeq);
#endif
// 這里(*outEvent不為NULL)杨帽,跳出while循環(huán)
break;
}
}
return result;
}
}
......
}
//返回
return OK;
}
status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory,
nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
status_t result;
for (size_t i = mBatches.size(); i > 0; ) {
i--;
Batch& batch = mBatches.editItemAt(i);
......
nsecs_t sampleTime = frameTime;
if (mResampleTouch) {
sampleTime -= RESAMPLE_LATENCY;
}
// 找到事件早于sampleTime的事件
ssize_t split = findSampleNoLaterThan(batch, sampleTime);
if (split < 0) {
continue;
}
// Batch中的事件合成一個MotionEvent
result = consumeSamples(factory, batch, split + 1, outSeq, outEvent);
const InputMessage* next;
if (batch.samples.isEmpty()) {
// Batch中無事件,移除Batch
mBatches.removeAt(i);
next = NULL;
} else {
// Batch中有晚于sampleTime的事件
next = &batch.samples.itemAt(0);
}
if (!result && mResampleTouch) {
// 重采樣嗤军,采樣事件信息存放到MotionEvent的mSamplexxx的最后
// View層獲取的Move事件的信息為采樣事件信息
// 針對next是否為NULL采樣兩種重采樣算法注盈,請參考http://www.masonchang.com/blog/2014/8/25/androids-touch-resampling-algorithm自行閱讀resampleTouchState實現(xiàn)
resampleTouchState(sampleTime, static_cast<MotionEvent*>(*outEvent), next);
}
return result;
}
無論直接處理還是Batch處理,最終都通過WindowInputEventReceiver
的dispatchInputEvent()
處理叙赚,下面分析該過程老客。
事件從ViewRootImpl傳遞至Activity的過程
下面從WindowInputEventReceiver
的OnInputEvent()
開始分析
public void onInputEvent(InputEvent event) {
// 調(diào)用enqueueInputEvent處理
enqueueInputEvent(event, this, 0, true);
}
void enqueueInputEvent(InputEvent event,
InputEventReceiver receiver, int flags, boolean processImmediately) {
// receiver為WindowInputEventReceiver
// flags為0, processImmediately為true
adjustInputEventForCompatibility(event);
// 事件封裝成QueuedInputEvent
QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
// Always enqueue the input event in order, regardless of its time stamp.
// We do this because the application or the IME may inject key events
// in response to touch events and we want to ensure that the injected keys
// are processed in the order they were received and we cannot trust that
// the time stamp of injected events are monotonic.
QueuedInputEvent last = mPendingInputEventTail;
// 事件插入待處理的事件隊列
if (last == null) {
mPendingInputEventHead = q;
mPendingInputEventTail = q;
} else {
last.mNext = q;
mPendingInputEventTail = q;
}
mPendingInputEventCount += 1;
// 更新systrace中,應(yīng)用內(nèi)"aq:pending:xxx"信息(增加計數(shù))
Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
mPendingInputEventCount);
if (processImmediately) {
// 立即處理事件
doProcessInputEvents();
} else {
scheduleProcessInputEvents();
}
}
void doProcessInputEvents() {
// Deliver all pending input events in the queue.
// 傳遞待處理事件隊列中所有事件
while (mPendingInputEventHead != null) {
QueuedInputEvent q = mPendingInputEventHead;
mPendingInputEventHead = q.mNext;
if (mPendingInputEventHead == null) {
mPendingInputEventTail = null;
}
q.mNext = null;
mPendingInputEventCount -= 1;
// 更新systrace中震叮,應(yīng)用內(nèi)"aq:pending:xxx信息"(減少計數(shù))
Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
mPendingInputEventCount);
// 對于Batch事件胧砰,eventTime為重采樣事件時間,oldestEventTime為Batch的首個Move事件的時間
long eventTime = q.mEvent.getEventTimeNano();
long oldestEventTime = eventTime;
if (q.mEvent instanceof MotionEvent) {
MotionEvent me = (MotionEvent)q.mEvent;
if (me.getHistorySize() > 0) {
oldestEventTime = me.getHistoricalEventTimeNano(0);
}
}
mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
// 傳遞輸入事件
deliverInputEvent(q);
}
......
}
下面看deliverInputEvent()
的實現(xiàn)
private void deliverInputEvent(QueuedInputEvent q) {
// systrace中苇瓣,應(yīng)用內(nèi)"deliverInputEvent"的開始
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
q.mEvent.getSequenceNumber());
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
}
InputStage stage;
// q.mFlags為0
if (q.shouldSendToSynthesizer()) {
stage = mSyntheticInputStage;
} else {
// 對于普通的MotionEvent shouldSkipIme返回true
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}
if (stage != null) {
// 傳遞給EarlyPostImeInputStage處理尉间,多個InputStage采用職責(zé)鏈模式
stage.deliver(q);
} else {
finishInputEvent(q);
}
}
下面看EarlyPostImeInputStage
的對MotionEvent
的處理
public final void deliver(QueuedInputEvent q) {
if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
forward(q);
} else if (shouldDropInputEvent(q)) {
finish(q, false);
} else {
// 調(diào)用onProcess處理,然后調(diào)用apply
apply(q, onProcess(q));
}
}
protected int onProcess(QueuedInputEvent q) {
if (q.mEvent instanceof KeyEvent) {
return processKeyEvent(q);
} else {
final int source = q.mEvent.getSource();
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
// 普通的MotionEvent為Pointer事件
return processPointerEvent(q);
}
}
return FORWARD;
}
private int processPointerEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
// Translate the pointer event for compatibility, if needed.
if (mTranslator != null) {
mTranslator.translateEventInScreenToAppWindow(event);
}
// Enter touch mode on down or scroll.
final int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
// 確保窗口處于touch模式
ensureTouchMode(true);
}
// Offset the scroll position.
if (mCurScrollY != 0) {
event.offsetLocation(0, mCurScrollY);
}
// Remember the touch position for possible drag-initiation.
if (event.isTouchEvent()) {
// 記錄坐標(biāo)击罪,對與Batch事件是重采樣坐標(biāo)
mLastTouchPoint.x = event.getRawX();
mLastTouchPoint.y = event.getRawY();
mLastTouchSource = event.getSource();
}
// 返回FORWARD
return FORWARD;
}
protected void apply(QueuedInputEvent q, int result) {
// 根據(jù)onProcess返回的結(jié)果哲嘲,進(jìn)行相應(yīng)的處理
if (result == FORWARD) {
// forward中調(diào)用onDeliverToNext
forward(q);
} else if (result == FINISH_HANDLED) {
finish(q, true);
} else if (result == FINISH_NOT_HANDLED) {
finish(q, false);
} else {
throw new IllegalArgumentException("Invalid result: " + result);
}
}
protected void onDeliverToNext(QueuedInputEvent q) {
if (DEBUG_INPUT_STAGES) {
Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q);
}
這里mNext為NativePostImeInputStage
if (mNext != null) {
mNext.deliver(q);
} else {
finishInputEvent(q);
}
}
EarlyPostImeInputStage
處理完事件后,傳遞給NativePostImeInputStage
處理媳禁,NativePostImeInputStage
的處理過程非常簡單眠副,下面直接看ViewPostImeInputStage
的處理。
protected int onProcess(QueuedInputEvent q) {
if (q.mEvent instanceof KeyEvent) {
return processKeyEvent(q);
} else {
final int source = q.mEvent.getSource();
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
// 處理Pointer MotionEvent
return processPointerEvent(q);
} else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
return processTrackballEvent(q);
} else {
return processGenericMotionEvent(q);
}
}
}
private int processPointerEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
mAttachInfo.mUnbufferedDispatchRequested = false;
// 這里eventTarget為mView也就是DecorView
final View eventTarget =
(event.isFromSource(InputDevice.SOURCE_MOUSE) && mCapturingView != null) ?
mCapturingView : mView;
mAttachInfo.mHandlingPointerEvent = true;
// 調(diào)用DecorView的dispatchPointerEvent方法
boolean handled = eventTarget.dispatchPointerEvent(event);
maybeUpdatePointerIcon(event);
mAttachInfo.mHandlingPointerEvent = false;
if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
mUnbufferedInputDispatch = true;
if (mConsumeBatchedInputScheduled) {
scheduleConsumeBatchedInputImmediately();
}
}
// handled為true竣稽,事件處理完成
// handled為false囱怕,事件沒有處理,繼續(xù)傳遞給下一個InputStage毫别,當(dāng)InputStage為null時娃弓,事件處理完成
return handled ? FINISH_HANDLED : FORWARD;
}
public final boolean dispatchPointerEvent(MotionEvent event) {
if (event.isTouchEvent()) {
// 調(diào)用dispatchTouchEvent繼續(xù)處理
return dispatchTouchEvent(event);
} else {
return dispatchGenericMotionEvent(event);
}
}
public boolean dispatchTouchEvent(MotionEvent ev) {
// 這里cb為Activity,Activity實現(xiàn)了Window.Callback
final Window.Callback cb = mWindow.getCallback();
return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}
至此拧烦,Motion事件已經(jīng)傳遞給Activity
忘闻,下面看Motion事件在Activity
窗口內(nèi)傳遞的過程。
Motion事件在Activity窗口內(nèi)傳遞的過程
下面從Activity
的dispatchTouchEvent()
開始分析
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
// 用戶交互回調(diào)
onUserInteraction();
}
// 調(diào)用PhoneWindow的superDispatchTouchEvent
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
// Activity內(nèi)沒有View處理(可處理窗口范圍外的事件)
return onTouchEvent(ev);
}
- 這里可以重寫
Activity
的dispatchTouchEvent
截獲所有Touch事件
下面看PhoneWindow
的superDispatchTouchEvent()
的實現(xiàn)
public boolean superDispatchTouchEvent(MotionEvent event) {
// 調(diào)用DecorView的superDispatchTouchEvent方法
return mDecor.superDispatchTouchEvent(event);
}
public boolean superDispatchTouchEvent(MotionEvent event) {
// DecorView繼承自FrameLayout, FrameLayout繼承自ViewGroup
// 調(diào)用ViewGroup的dispatchTouchEvent方法
return super.dispatchTouchEvent(event);
}
下面分析ViewGroup
的dispatchTouchEvent()
實現(xiàn)
public boolean dispatchTouchEvent(MotionEvent ev) {
// 用于調(diào)試目的
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
}
......
// 根據(jù)安全策略過濾事件
if (onFilterTouchEventForSecurity(ev)) {
final int action = ev.getAction();
final int actionMasked = action & MotionEvent.ACTION_MASK;
// Handle an initial down.
// Down事件恋博,清理TouchState
if (actionMasked == MotionEvent.ACTION_DOWN) {
// Throw away all previous state when starting a new touch gesture.
// The framework may have dropped the up or cancel event for the previous gesture
// due to an app switch, ANR, or some other state change.
// 清理先前Touch事件的TouchStage齐佳,通常不需要(up事件時會清理),但在app switch债沮、ANR等一些情況下
// 之前的Touch事件的up/cancel事件可能被丟棄
cancelAndClearTouchTargets(ev);
resetTouchState();
}
// Check for interception.
// 檢查是否需要攔截事件
final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
// 檢查是否攔截炼吴,默認(rèn)不攔截Motion事件,子類可重寫
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action); // restore action in case it was changed
} else {
intercepted = false;
}
} else {
// There are no touch targets and this action is not an initial down
// so this view group continues to intercept touches.
// 對于非Down事件疫衩,如果沒有touch targets硅蹦,攔截
intercepted = true;
}
// Check for cancelation.
// 檢查是否需要取消
final boolean canceled = resetCancelNextUpFlag(this)
|| actionMasked == MotionEvent.ACTION_CANCEL;
......
if (!canceled && !intercepted) {
// If the event is targeting accessiiblity focus we give it to the
// view that has accessibility focus and if it does not handle it
// we clear the flag and dispatch the event to all children as usual.
// We are looking up the accessibility focused host to avoid keeping
// state since these events are very rare.
View childWithAccessibilityFocus = ev.isTargetAccessibilityFocus()
? findChildWithAccessibilityFocus() : null;
// 對于Down事件
if (actionMasked == MotionEvent.ACTION_DOWN
|| (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
final int actionIndex = ev.getActionIndex(); // always 0 for down
final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
: TouchTarget.ALL_POINTER_IDS;
......
final int childrenCount = mChildrenCount;
if (newTouchTarget == null && childrenCount != 0) {
final float x = ev.getX(actionIndex);
final float y = ev.getY(actionIndex);
// Find a child that can receive the event.
// Scan children from front to back.
// 從前到后查找子View,找到能夠接收事件的孩子
final ArrayList<View> preorderedList = buildTouchDispatchChildList();
final boolean customOrder = preorderedList == null
&& isChildrenDrawingOrderEnabled();
final View[] children = mChildren;
for (int i = childrenCount - 1; i >= 0; i--) {
final int childIndex = getAndVerifyPreorderedIndex(
childrenCount, i, customOrder);
final View child = getAndVerifyPreorderedView(
preorderedList, children, childIndex);
......
// View是否可以接收Pointer事件闷煤,事件坐標(biāo)是否在View區(qū)域內(nèi)
if (!canViewReceivePointerEvents(child)
|| !isTransformedTouchPointInView(x, y, child, null)) {
ev.setTargetAccessibilityFocus(false);
continue;
}
newTouchTarget = getTouchTarget(child);
// 分發(fā)Down事件給子View
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
// Child wants to receive touch within its bounds.
// 子View處理了事件
mLastTouchDownTime = ev.getDownTime();
if (preorderedList != null) {
// childIndex points into presorted list, find original index
for (int j = 0; j < childrenCount; j++) {
if (children[childIndex] == mChildren[j]) {
mLastTouchDownIndex = j;
break;
}
}
} else {
mLastTouchDownIndex = childIndex;
}
mLastTouchDownX = ev.getX();
mLastTouchDownY = ev.getY();
// 子View封裝為TouchTarget童芹,添加到TouchTarget鏈表中
newTouchTarget = addTouchTarget(child, idBitsToAssign);
alreadyDispatchedToNewTouchTarget = true;
break;
}
......
}
......
}
}
}
// Dispatch to touch targets.
if (mFirstTouchTarget == null) {
// 沒有touch targets,ViewGroup像普通View一樣分發(fā)
// No touch targets so treat this as an ordinary view.
handled = dispatchTransformedTouchEvent(ev, canceled, null,
TouchTarget.ALL_POINTER_IDS);
} else {
// Dispatch to touch targets, excluding the new touch target if we already
// dispatched to it. Cancel touch targets if necessary.
TouchTarget predecessor = null;
TouchTarget target = mFirstTouchTarget;
// 遍歷TouchTarget鏈表分發(fā)事件
while (target != null) {
final TouchTarget next = target.next;
if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
// 已經(jīng)分發(fā)給該TouchTarget鲤拿,如Down事件
handled = true;
} else {
final boolean cancelChild = resetCancelNextUpFlag(target.child)
|| intercepted;
// 分發(fā)非Down事件給TouchTarget對應(yīng)的子View
// 如果cancelChild為true假褪,分發(fā)CANCEL事件
if (dispatchTransformedTouchEvent(ev, cancelChild,
target.child, target.pointerIdBits)) {
handled = true;
}
if (cancelChild) {
// cancelChild為true,刪除當(dāng)前的TouchTarget
if (predecessor == null) {
mFirstTouchTarget = next;
} else {
predecessor.next = next;
}
target.recycle();
target = next;
continue;
}
}
predecessor = target;
target = next;
}
}
// Update list of touch targets for pointer up or cancel, if needed.
if (canceled
|| actionMasked == MotionEvent.ACTION_UP
|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
// 如果是CANCEL或者UP事件近顷,重置TouchState
resetTouchState();
} else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
final int actionIndex = ev.getActionIndex();
final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
removePointersFromTouchTargets(idBitsToRemove);
}
}
......
// 返回處理結(jié)果
return handled;
}
這里簡單總結(jié)下Touch事件的處理:
- 處理Down事件時生音,確定TouchTarget樹,此后MOVE/UP事件沿著TouchTarget樹分發(fā)
- 分發(fā)MOVE/UP事件時窒升,如果中途被攔截缀遍,則向子樹發(fā)送CANCEL事件,刪除子View對應(yīng)的TouchTarget
- 處理UP/CANCEL事件時饱须,會重置TouchTarget
對于后續(xù)的處理過程域醇,這里暫不討論,請自行擼碼蓉媳,歡迎討論交流歹苦。