Android Input(六)-ViewRootImpl接收事
上一篇讲到,客户端的主线程的Looper会监控socket pair的客户端fd,一旦服务端(InputDispatcher)发送Input Event到socket pair的服务端 ,则客户端的Looper就会被唤醒,并调用NaitveInputEventReceiver的handleEvent()函数。
frameworks/base/core/jni/android_view_InputEventReceiver.cpp
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
...
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;
}
...
}
执行consumeEvents
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env, bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
...
ScopedLocalRef<jobject> receiverObj(env, NULL);
bool skipCallbacks = false;
for (;;) {
uint32_t seq;
InputEvent* inputEvent;
// 读取InputEvent
status_t status = mInputConsumer.consume(&mInputEventFactory, consumeBatches, frameTime, &seq, &inputEvent);
...
switch (inputEvent->getType()) {
case AINPUT_EVENT_TYPE_KEY:
// 根据读取到的InputEvent,构建java层的KeyEvent
inputEventObj = android_view_KeyEvent_fromNative(env, static_cast<KeyEvent*>(inputEvent));
break;
case AINPUT_EVENT_TYPE_MOTION: {
...
}
if (inputEventObj) {
// 调用java层的InputEventReceiver.dispachInputEvent()
env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
env->DeleteLocalRef(inputEventObj);
}
...
}
这里有两个部分内容:
一、读取input事件并构建java层的KeyEvent
frameworks/native/libs/input/InputTransport.cpp
status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent)
*outSeq = 0;
*outEvent = NULL;
while (!*outEvent) {
...
// Receive a fresh message.
status_t result = mChannel->receiveMessage(&mMsg);}
if (result) {
...
return result;
}
}
switch (mMsg.header.type) {
case InputMessage::TYPE_KEY: {this
KeyEvent* keyEvent = factory->createKeyEvent();
initializeKeyEvent(keyEvent, &mMsg);
*outSeq = mMsg.body.key.seq;
*outEvent = keyEvent;
break;
}
...
}
通过InputChannel获取到InputEvent 转为Native的KeyEvent,最终再转化为java层的KeyEvent,此处不铺开分析了。
二、分发事件
2.1 QueuedInputEvent构建
frameworks/base/core/java/android/view/InputEventReceiver.java
public abstract class InputEventReceiver {
private void dispatchInputEvent(int seq, InputEvent event) {
mSeqMap.put(event.getSequenceNumber(), seq);
onInputEvent(event);
}
这里的InputEventReceiver是ViewRootImpl的内部类WindowInputEventReceiver:
frameworks/base/core/java/android/view/ViewRootImpl.java
final class WindowInputEventReceiver extends InputEventReceiver {
public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
}
public void onInputEvent(InputEvent event) {
enqueueInputEvent(event, this, 0, true);
}
}
子类的onInputEvent中执行enqueueInputEvent
void enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately) {
adjustInputEventForCompatibility(event);
// 构建一个QueueInputEvent,插入到pending队列尾部
QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
...
// 处理pending队列里的event
if (processImmediately) {
doProcessInputEvents();//立刻执行
} else {
scheduleProcessInputEvents();//延迟执行
}
}
void doProcessInputEvents() {
// Deliver all pending input events in the queue.
while (mPendingInputEventHead != null) {
QueuedInputEvent q = mPendingInputEventHead;
...
deliverInputEvent(q);//分发事件
}
...
}
2.2 InputStage体系
private void deliverInputEvent(QueuedInputEvent q) {
...
InputStage stage;
//这里是stage实现类
if (q.shouldSendToSynthesizer()) {
stage = mSyntheticInputStage;
} else {
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}
if (stage != null) {
stage.deliver(q);
} else {
finishInputEvent(q);//完成事件分发处理
}
}
那么看看子类初始化的地方:
frameworks/base/core/java/android/view/ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
…
mSyntheticInputStage = new SyntheticInputStage();
InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
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;
}
构造了7个InputStage实现类,
-
NativePreImeInputStage
: 主要是为了将消息放到NativeActivity中去处理, NativeActivity和普通Acitivty的功能区别不大,只是很多代码都在native层去实现,这样执行效率更高,并且NativeActivity在游戏开发中很实用。 -
ViewPreImeInputStage
: 从名字中就可得知,最后会调用Acitivity的所有view的onkeyPreIme方法,这样就给View在输入法处理key事件之前先得到消息并处理的机会。 -
ImeInputStage
: ImeInputStage的onProcess方法会调用InputMethodManager的dispatchInputEvent方法处理消息。 -
EarlyPostImeInputStage
: 屏幕上有焦点的View会高亮显示,用来提示用户焦点所在。 -
NativePostImeInputStage
: 为了让IME处理完消息后能先于普通的Activity处理消息。 -
ViewPostImeInputStage
: Acitivity和view处理各种消息。 -
SyntheticInputStage
: 流水线的最后一级,经过层层过滤之后,到达这里的消息已经不多了,例如手机上的虚拟按键消息。
那么Activity和View的事件处理主要对应的InputStage是ViewPostImeInputStage。
实现关系如下图所示:
关系图InputStage体系是很明显的责任链模式,自己能处理的就处理,不能处理的就next下去交给下一个处理。
abstract class InputStage {
private final InputStage mNext;
protected static final int FORWARD = 0;
protected static final int FINISH_HANDLED = 1;
protected static final int FINISH_NOT_HANDLED = 2;
/**
* Creates an input stage.
* @param next The next stage to which events should be forwarded.
*/
public InputStage(InputStage next) {
mNext = next;
}
/**
* Delivers an event to be processed.
*/
public final void deliver(QueuedInputEvent q) {
if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
forward(q);//分发给下一个InputStage对象来处理
} else if (shouldDropInputEvent(q)) { //是否需要丢弃
finish(q, false);
} else {
apply(q, onProcess(q));
}
}
/**
* Marks the the input event as finished then forwards it to the next stage.
*/
protected void finish(QueuedInputEvent q, boolean handled) {
q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
if (handled) {
//Finish方法会给这个消息加上FLAG_FINISHED标志,这样后面的InputStage对象也不会处理了,一直到流水线的结尾。
q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
}
forward(q);
}
/**
* Forwards the event to the next stage.
*/
protected void forward(QueuedInputEvent q) {
onDeliverToNext(q);
}
/**
* Applies a result code from {@link #onProcess} to the specified event.
*/
protected void apply(QueuedInputEvent q, int result) {
if (result == FORWARD) {
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);
}
}
/**
* Called when an event is ready to be processed.
* @return A result code indicating how the event was handled.
*/
protected int onProcess(QueuedInputEvent q) {
return FORWARD;
}
/**
* Called when an event is being delivered to the next stage.
*/
protected void onDeliverToNext(QueuedInputEvent q) {
if (DEBUG_INPUT_STAGES) {
Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q);
}
if (mNext != null) {
mNext.deliver(q);//调用下一级来进行处理
} else {
finishInputEvent(q);//如果是最后一级,直接finish
}
}
protected boolean shouldDropInputEvent(QueuedInputEvent q) {
if (mView == null || !mAdded) {
Slog.w(mTag, "Dropping event due to root view being removed: " + q.mEvent);
return true;
} else if ((!mAttachInfo.mHasWindowFocus
&& !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) || mStopped
|| (mIsAmbientMode && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_BUTTON))
|| (mPausedForTransition && !isBack(q.mEvent))) {
// This is a focus event and the window doesn't currently have input focus or
// has stopped. This could be an event that came back from the previous stage
// but the window has lost focus or stopped in the meantime.
if (isTerminalInputEvent(q.mEvent)) {
// Don't drop terminal input events, however mark them as canceled.
q.mEvent.cancel();
Slog.w(mTag, "Cancelling event due to no window focus: " + q.mEvent);
return false;
}
// Drop non-terminal input events.
Slog.w(mTag, "Dropping event due to no window focus: " + q.mEvent);
return true;
}
return false;
}
void dump(String prefix, PrintWriter writer) {
if (mNext != null) {
mNext.dump(prefix, writer);
}
}
private boolean isBack(InputEvent event) {
if (event instanceof KeyEvent) {
return ((KeyEvent) event).getKeyCode() == KeyEvent.KEYCODE_BACK;
} else {
return false;
}
}
}
几个主要操作:
forword(q)
: 分发给下一个InputStage对象来处理。
shouldDropInputEvent(q)
: 是否需要丢弃。
finish(q, false)
: 加FLAG_FINISHED_HANDLED标签,后面的InputStage对象不会处理了。
onProcess(q)
:实现类重写此方法,真正事件的分发操作是从这开始的。
apply(q, onProcess(q))
: 根据result做出对应处理。
result类型:
-
FORWARD
: 本InputStage对象未处理,调用forward方法给下一个InputStage对象处理。 -
FINISH_HANDLED
: 本InputStage对象已处理,直接finish。 -
FINISH_NOT_HANDLED
: 消息虽然没有处理,但是要结束,调用finish方法结束。
最后放一张流程图:
ViewRootImpl接收消息流程