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 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(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。

实现关系如下图所示:

Android Input(六)-ViewRootImpl接收事件_第1张图片
关系图

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方法结束。

最后放一张流程图:

Android Input(六)-ViewRootImpl接收事件_第2张图片
ViewRootImpl接收消息流程

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

你可能感兴趣的:(Android Input(六)-ViewRootImpl接收事件)