Android Input(六)-ViewRootImpl接收事

作者: Stan_Z | 来源:发表于2019-07-02 17:06 被阅读77次

    上一篇讲到,客户端的主线程的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接收消息流程

    下一篇文章:
    Android Input(七)-ViewRootImpl处理事件

    相关文章

      网友评论

        本文标题:Android Input(六)-ViewRootImpl接收事

        本文链接:https://www.haomeiwen.com/subject/jndthctx.html