从手触摸到屏幕开始
当屏幕被触摸之后,linux内核会将屏幕产生的触摸事件封装为event保存到/dev/input/event[x]节点下,接着系统创建的InputReaderThread线程Loop起来让EventHub调用getEvent不断的从/dev/input/节点下读取输入事件,然后InputReader线程将从EventHub读取的事件交给InputDispatch,InputDispatch则将事件分发到x需要的地方,譬如ViewRootImpl的WindowInputEventReceiver,这部分的逻辑主要是c++实现的,事件分发到ViewRootImpl之后也就是分发到了框架层,后续的事件就会通过一系列分发传递给decorView,然后传递给PhoneWindow,后续又回到DecorView,然后从这个顶级的view树节点向下分发
1.0Decorview的添加过程
不管是activity,dialog还是PopupWindow,其窗口的添加过程最终都是调用windowmanager的addView来实现的,windowmanager是一个接口,其最终是调用windowmanagerglobal的addView来实现的
root = new ViewRootImpl(view.getContext(), display);//创建一个ViewRootImpl对象
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
// do this last because it fires off messages to start doing things
try {
root.setView(view, wparams, panelParentView);//调用setView方法
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);//异常处理操作
}
throw e;
}
1.1ViewRootImpl的setView方法
requestLayout();//请求布局
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();//创建InputChannel对象
}
mForceDecorViewVisibility = (mWindowAttributes.privateFlags
& PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,//调用windowsession的addToDisplay方法
getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
} catch (RemoteException e) {
mAdded = false;
mView = null;
mAttachInfo.mRootView = null;
mInputChannel = null;
mFallbackEventHandler.setView(null);
unscheduleTraversals();
setAccessibilityFocus(null, null);
throw new RuntimeException("Adding window failed", e);
} finally {
if (restore) {
attrs.restore();
}
}
接着关注下半部分
if (mInputChannel != null) {//如果inputChannel不为空的时候
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
}
view.assignParent(this);
mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
if (mAccessibilityManager.isEnabled()) {
mAccessibilityInteractionConnectionManager.ensureConnection();
}
if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
}
// Set up the input pipeline.
CharSequence counterSuffix = attrs.getTitle();
mSyntheticInputStage = new SyntheticInputStage();
InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);//创建InputStage对象
InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
"aq:native-post-ime:" + counterSuffix);
InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
InputStage imeStage = new ImeInputStage(earlyPostImeStage,
"aq:ime:" + counterSuffix);
InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
"aq:native-pre-ime:" + counterSuffix);
mFirstInputStage = nativePreImeStage;
mFirstPostImeInputStage = earlyPostImeStage;
mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
从上面的代码我们看到创建了两个对象WindowInputEventReceiver和InputStage对象
1.2从WindowInputEventReceiver开始
WindowInputEventReceiver是ViewRootImpl的内部类
final class WindowInputEventReceiver extends InputEventReceiver {
public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
}
@Override
public void onInputEvent(InputEvent event, int displayId) {
enqueueInputEvent(event, this, 0, true);
}
@Override
public void onBatchedInputEventPending() {
if (mUnbufferedInputDispatch) {
super.onBatchedInputEventPending();
} else {
scheduleConsumeBatchedInput();
}
}
@Override
public void dispose() {
unscheduleConsumeBatchedInput();
super.dispose();
}
WindowInputEventReceiver是InputEventReceiver的子类
1.3InputEventReceiver
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
if (inputChannel == null) {
throw new IllegalArgumentException("inputChannel must not be null");
}
if (looper == null) {
throw new IllegalArgumentException("looper must not be null");
}
mInputChannel = inputChannel;
mMessageQueue = looper.getQueue();//looper对应的消息队列
mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
inputChannel, mMessageQueue);//会调用到android_view_InputEventReceiver.cpp
mCloseGuard.open("dispose");
}
1.4InputEventReceiver.cpp
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject inputChannelObj, jobject messageQueueObj) {
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);//将java对象转化为c++对象
if (inputChannel == NULL) {
jniThrowRuntimeException(env, "InputChannel is not initialized.");
return 0;
}
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
//根据java层的inputchannel对象和Looper对象创建c++层的NativeInputEventReceiver 对象
sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
receiverWeak, inputChannel, messageQueue);
status_t status = receiver->initialize();
if (status) {
String8 message;
message.appendFormat("Failed to initialize input event receiver. status=%d", status);
jniThrowRuntimeException(env, message.string());
return 0;
}
receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object
return reinterpret_cast<jlong>(receiver.get());
}
NativeInputEventReceiver作用
NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env,
jobject receiverWeak, const sp<InputChannel>& inputChannel,
const sp<MessageQueue>& messageQueue) :
mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
mInputConsumer(inputChannel), mMessageQueue(messageQueue),
mBatchedInputEventPending(false), mFdEvents(0) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Initializing input event receiver.", getInputChannelName().c_str());
}
}
status_t NativeInputEventReceiver::initialize() {
setFdEvents(ALOOPER_EVENT_INPUT);
return OK;
}
NativeInputEventReceiver有一个私有的mInputConsumer变量,就是生成一个mInputConsumer并且调用initialize方法初始化,将inputChannel的fd挂载到looper中去监听事件,回调函数为handleEvent
1.5setFdEvents的实现
void NativeInputEventReceiver::setFdEvents(int events) {
if (mFdEvents != events) {
mFdEvents = events;
int fd = mInputConsumer.getChannel()->getFd();
if (events) {
mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
} else {
mMessageQueue->getLooper()->removeFd(fd);
}
}
}
1.6handleEvent
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
// This error typically occurs when the publisher has closed the input channel
// as part of removing a window or finishing an IME session, in which case
// the consumer will soon be disposed as well.
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Publisher closed input channel or an error occurred. "
"events=0x%x", getInputChannelName().c_str(), events);
}
return 0; // remove the callback
}
if (events & ALOOPER_EVENT_INPUT) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);
mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
return status == OK || status == NO_MEMORY ? 1 : 0;
}
if (events & ALOOPER_EVENT_OUTPUT) {
for (size_t i = 0; i < mFinishQueue.size(); i++) {
const Finish& finish = mFinishQueue.itemAt(i);
status_t status = mInputConsumer.sendFinishedSignal(finish.seq, finish.handled);
if (status) {
mFinishQueue.removeItemsAt(0, i);
if (status == WOULD_BLOCK) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Sent %zu queued finish events; %zu left.",
getInputChannelName().c_str(), i, mFinishQueue.size());
}
return 1; // keep the callback, try again later
}
ALOGW("Failed to send finished signal on channel '%s'. status=%d",
getInputChannelName().c_str(), status);
if (status != DEAD_OBJECT) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
String8 message;
message.appendFormat("Failed to finish input event. status=%d", status);
jniThrowRuntimeException(env, message.string());
mMessageQueue->raiseAndClearException(env, "finishInputEvent");
}
return 0; // remove the callback
}
}
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Sent %zu queued finish events; none left.",
getInputChannelName().c_str(), mFinishQueue.size());
}
mFinishQueue.clear();
setFdEvents(ALOOPER_EVENT_INPUT);
return 1;
}
ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. "
"events=0x%x", getInputChannelName().c_str(), events);
return 1;
}
1.7ConsumeEvent
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Consuming input events, consumeBatches=%s, frameTime=%" PRId64,
getInputChannelName().c_str(),
consumeBatches ? "true" : "false", frameTime);
}
if (consumeBatches) {
mBatchedInputEventPending = false;
}
if (outConsumedBatch) {
*outConsumedBatch = false;
}
ScopedLocalRef<jobject> receiverObj(env, NULL);
bool skipCallbacks = false;
for (;;) {
uint32_t seq;
InputEvent* inputEvent;
int32_t displayId;
status_t status = mInputConsumer.consume(&mInputEventFactory,
consumeBatches, frameTime, &seq, &inputEvent, &displayId);
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().c_str());
return DEAD_OBJECT;
}
}
mBatchedInputEventPending = true;
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Dispatching batched input event pending notification.",
getInputChannelName().c_str());
}
env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchBatchedInputEventPending);
if (env->ExceptionCheck()) {
ALOGE("Exception dispatching batched input events.");
mBatchedInputEventPending = false; // try again later
}
}
return OK;
}
ALOGE("channel '%s' ~ Failed to consume input event. status=%d",
getInputChannelName().c_str(), status);
return status;
}
assert(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().c_str());
return DEAD_OBJECT;
}
}
jobject inputEventObj;
switch (inputEvent->getType()) {
case AINPUT_EVENT_TYPE_KEY:
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Received key event.", getInputChannelName().c_str());
}
inputEventObj = android_view_KeyEvent_fromNative(env,
static_cast<KeyEvent*>(inputEvent));
break;
case AINPUT_EVENT_TYPE_MOTION: {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Received motion event.", getInputChannelName().c_str());
}
MotionEvent* motionEvent = static_cast<MotionEvent*>(inputEvent);
if ((motionEvent->getAction() & AMOTION_EVENT_ACTION_MOVE) && outConsumedBatch) {
*outConsumedBatch = true;
}
inputEventObj = android_view_MotionEvent_obtainAsCopy(env, motionEvent);
break;
}
default:
assert(false); // InputConsumer should prevent this from ever happening
inputEventObj = NULL;
}
if (inputEventObj) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName().c_str());
}
env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj,
displayId);//回调java层的dispatchInputEvent方法
if (env->ExceptionCheck()) {
ALOGE("Exception dispatching input event.");
skipCallbacks = true;
}
env->DeleteLocalRef(inputEventObj);
} else {
ALOGW("channel '%s' ~ Failed to obtain event object.",
getInputChannelName().c_str());
skipCallbacks = true;
}
}
if (skipCallbacks) {
mInputConsumer.sendFinishedSignal(seq, false);
}
}
}
1.8InputEventReceiver之dispatchInputEvent
private void dispatchInputEvent(int seq, InputEvent event, int displayId) {
mSeqMap.put(event.getSequenceNumber(), seq);
onInputEvent(event, displayId);
}
这个方法已经被子类WindowInputEventReceiver复写了
@Override
public void onInputEvent(InputEvent event, int displayId) {
enqueueInputEvent(event, this, 0, true);
}
1.9onInputEvent
内部调用的是enqueueInputEvent方法
void enqueueInputEvent(InputEvent event,
InputEventReceiver receiver, int flags, boolean processImmediately) {
adjustInputEventForCompatibility(event);
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;
Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
mPendingInputEventCount);
if (processImmediately) {
doProcessInputEvents();
} else {
scheduleProcessInputEvents();
}
1.10doProcessInputEvents
我们从上面的方法可以看到此时传递过来的processImmediately为true,我们看下
doProcessInputEvents方法
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;
Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
mPendingInputEventCount);
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);
}
// We are done processing all input events that we can process right now
// so we can clear the pending flag immediately.
if (mProcessInputEventsScheduled) {
mProcessInputEventsScheduled = false;
mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
}
}
这里有一个while循环,主要的作用是将事件从队列中循环处理,直到队列中没有事件为止,我们看下deliverInputEvent方法的实现
1.11deliverInputEvent
private void deliverInputEvent(QueuedInputEvent q) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
q.mEvent.getSequenceNumber());
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
}
InputStage stage;
if (q.shouldSendToSynthesizer()) {
stage = mSyntheticInputStage;
} else {
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}
if (q.mEvent instanceof KeyEvent) {
mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
}
//上面是决定事件分发到那个InputStage中处理
if (stage != null) {
handleWindowFocusChanged();
stage.deliver(q);//派发事件到InputStage中处理
} else {
finishInputEvent(q);
}
}
InputStage是在setView方法中创建的,相当于一个单链表结构,也就是说,比如调用了mFirstPostImeInputStage.deliver(q)。那么SyntheticInputStage, ViewPostImeInputStage, NativePostImeInputStage, EarlyPostImeInputStage都将能够处理这个触摸事件。这里我们主要看看ViewPostImeInputStage是如何处理的。
1.12ViewPostImeInputStage
@Override
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) {
return processPointerEvent(q);//处理点触摸事件
} else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
return processTrackballEvent(q);
} else {
return processGenericMotionEvent(q);
}
}
}
@Override
protected void onDeliverToNext(QueuedInputEvent q) {
if (mUnbufferedInputDispatch
&& q.mEvent instanceof MotionEvent
&& ((MotionEvent)q.mEvent).isTouchEvent()
&& isTerminalInputEvent(q.mEvent)) {
mUnbufferedInputDispatch = false;
scheduleConsumeBatchedInput();
}
super.onDeliverToNext(q);
}
1.13processPointerEvent
private int processPointerEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
mAttachInfo.mUnbufferedDispatchRequested = false;
mAttachInfo.mHandlingPointerEvent = true;
boolean handled = mView.dispatchPointerEvent(event);//调用view的方法
maybeUpdatePointerIcon(event);
maybeUpdateTooltip(event);
mAttachInfo.mHandlingPointerEvent = false;
if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
mUnbufferedInputDispatch = true;
if (mConsumeBatchedInputScheduled) {
scheduleConsumeBatchedInputImmediately();
}
}
return handled ? FINISH_HANDLED : FORWARD;
}
上面的view就是我们addView的时候赋值的,也就是decorView,这样事件也就传递给了view
1.14dispatchPointerEvent
我们知道DecorView的直接父类是FrameLayout,我们搜索下Decorview下没有dispatchPointerEvent,那么直接进入到View的dispatchPointerEvent方法
public final boolean dispatchPointerEvent(MotionEvent event) {
if (event.isTouchEvent()) {//是否是触摸事件
return dispatchTouchEvent(event);
} else {
return dispatchGenericMotionEvent(event);
}
}
由于子类DecorView复写了dispatchTouchEvent,进入到DecorView的dispatchTouchEvent方法
1.15DecorView之dispatchTouchEvent
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final Window.Callback cb = mWindow.getCallback();
return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}
我们知道Activity实现了Window.Callback接口,这里调用的是
1.16Activity之disPatchTouchEvent
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {//PhoneWindow
return true;
}
return onTouchEvent(ev);
}
1.17PhoneWindow之superDispatchTouchEvent
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);//又回到了mDeCorView
}
1.18DecorView之superDispatchTouchEvent
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);//super值得是ViewGroup
}
1.19ViewGroup之dispatchTouchEvent
// Check for interception.
final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev);//是否继续分发,这个方法只有ViewGroup存在
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.
intercepted = true;
}
这样整个事件就从view的顶端向下分发了,流向是DecorView--->ViewGroup---->View
网友评论