Client 对输入事件处理

输入事件,比如按键事件并不是全部被window的view处理了,比如Back键,如果此时系统输入法是显示的,其实该键首先会去关闭输入法,而window的view是接收不到这个键的,这个就是事件处理器链实现的,这个链上又各种处理器,它们按照处理的优先顺序添加咋链表上

输入事件处理链

public abstract class InputEventReceiver {    //native收到输入事件是最终会回调到该函数    private void dispatchInputEvent(int seq, InputEvent event) {        mSeqMap.put(event.getSequenceNumber(), seq);        onInputEvent(event);    }}   final class WindowInputEventReceiver extends InputEventReceiver {        @Override        public void onInputEvent(InputEvent event) {            enqueueInputEvent(event, this, 0, true);        }    }    void enqueueInputEvent(InputEvent event) {        enqueueInputEvent(event, null, 0, false);    }    void enqueueInputEvent(InputEvent event,            InputEventReceiver receiver, int flags, boolean processImmediately) {        QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);        QueuedInputEvent last = mPendingInputEventTail;        if (last == null) {            mPendingInputEventHead = q;            mPendingInputEventTail = q;        } else {            last.mNext = q;            mPendingInputEventTail = q;        }        mPendingInputEventCount += 1;        if (processImmediately) {            //处理事件            doProcessInputEvents();        } else {            scheduleProcessInputEvents();        }    }    void doProcessInputEvents() {        // 遍历所有的输入事件        while (mPendingInputEventHead != null) {            QueuedInputEvent q = mPendingInputEventHead;            mPendingInputEventHead = q.mNext;            if (mPendingInputEventHead == null) {                mPendingInputEventTail = null;            }            q.mNext = null;            mPendingInputEventCount -= 1;            //处理事件            deliverInputEvent(q);        }    }    private void deliverInputEvent(QueuedInputEvent q) {        try {            //检测ime相关module是否需要处理该输入事件,比如back键,是需要先            //让IME处理,这个时候需要先交给mFirstPostImeInputStage处理            InputStage stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;            if (stage != null) {                stage.deliver(q);            } else {                //                finishInputEvent(q);            }        }    }       //大部分时候stage= mFirstInputStage,这个变量在最开始的时候赋值       InputStage syntheticInputStage = new SyntheticInputStage();       InputStage viewPostImeStage = new ViewPostImeInputStage(syntheticInputStage);       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;<div>       abstract class InputStage {        public final void deliver(QueuedInputEvent q) {            if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {                //已经被处理了,则让后面的处理                forward(q);            } else if (shouldDropInputEvent(q)) {                finish(q, false);            } else {                //没有处理,自己开始处理该事件                apply(q, onProcess(q));            }        }                protected void apply(QueuedInputEvent q, int result) {            if (result == FORWARD) {                forward(q);            } else if (result == FINISH_HANDLED) {                finish(q, true);            }        }        protected void forward(QueuedInputEvent q) {            onDeliverToNext(q);        }        protected void onDeliverToNext(QueuedInputEvent q) {            //如果下一个事件处理器不为空,则让下一个事件处理器处理            if (mNext != null) {                mNext.deliver(q);            } else {               //所有的都处理器都完成了处理,调用finish告知server端事件已经被处理                finishInputEvent(q);            }        }}    //将事件发送给view的事件处理器是ViewPostImeInputStage    final class ViewPostImeInputStage extends InputStage {        @Override        protected int onProcess(QueuedInputEvent q) {            if (q.mEvent instanceof KeyEvent) {                return processKeyEvent(q);            }        }        private int processKeyEvent(QueuedInputEvent q) {            final KeyEvent event = (KeyEvent)q.mEvent;            if (event.getAction() != KeyEvent.ACTION_UP) {                // If delivering a new key event, make sure the window is                // now allowed to start updating.                handleDispatchDoneAnimating();            }            // 向view发送按键事件            if (mView.dispatchKeyEvent(event)) {                return FINISH_HANDLED;            }            // 系统默认按键处理,比如CAMERA快捷键处理            if (mFallbackEventHandler.dispatchKeyEvent(event)) {                return FINISH_HANDLED;            }            return FORWARD;        }    } 


从上面的逻辑可以看出处理器的处理有限顺序是:

NativePreImeInputStage->ViewPreImeInputStage-> ImeInputStage->

EarlyPostImeInputStage-> NativePostImeInputStage->ViewPostImeInputStage->

SyntheticInputStage

Back按键如何结束Activity

刚刚前面说到,view获得输入事件是由ViewPostImeInputStage传递过来的。ViewPostImeInputStage会将事件传递给activity的根View ---DecorView

   private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {        @Override        public boolean dispatchKeyEvent(KeyEvent event) {            if (!isDestroyed()) {                //首先让callback处理,然后调用super的接口                final Callback cb = getCallback() && mFeatureId < 0 ? cb.dispatchKeyEvent(event)                        : super.dispatchKeyEvent(event);                if (handled) {                    return true;                }            }            return isDown ? PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event)                    : PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event);        }   }   //上面的getCallback的返回值就是Activity,故其有很高的优先级获取并处理这些按键。   public boolean onKeyDown(int keyCode, KeyEvent event)  {        if (keyCode == KeyEvent.KEYCODE_BACK) {            if (getApplicationInfo().targetSdkVersion                    >= Build.VERSION_CODES.ECLAIR) {            } else {                //这个就是结束activity的函数                onBackPressed();            }            return true;        }    }

如果非back按键,则会调用super即View.dispatchKeyEvent的接口,view的事件接收及处理就是从这开始的。

View如何获取按键

由于DecorView继承FrameLayout,它自然是一个ViewGroup,所以我们来看下ViewGroup的dispatchKeyEvent。

    @Override    public boolean dispatchKeyEvent(KeyEvent event) {        if (mInputEventConsistencyVerifier != null) {            mInputEventConsistencyVerifier.onKeyEvent(event, 1);        }        if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))                == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {            //调用view的接口            if (super.dispatchKeyEvent(event)) {                return true;            }        } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)                == PFLAG_HAS_BOUNDS) {            //向获得焦点的view传递事件            if (mFocused.dispatchKeyEvent(event)) {                return true;            }        }        return false;    }    public boolean dispatchKeyEvent(KeyEvent event) {        if (event.dispatch(this, mAttachInfo != null                ? mAttachInfo.mKeyDispatchState : null, this)) {            return true;        }        return false;    }    public final boolean dispatch(Callback receiver, DispatcherState state,            Object target) {        switch (mAction) {            case ACTION_DOWN: {                mFlags &= ~FLAG_START_TRACKING;                //这个就是我们的常见的onKeyDown,onKeyUp接口的调用                boolean res = receiver.onKeyDown(mKeyCode, this);                return res;            }        }        return false;    }


Camera等快捷键是如何传递处理的

如果view没有处理按键,则最后会给mFallbackEventHandler一个机会处理按键,Camera等快捷键就是由这个handler处理的,下面来看看。

public ViewRootImpl(Context context, Display display) {       mFallbackEventHandler= PolicyManager.makeNewFallbackEventHandler(context);}public class Policy implements IPolicy {public FallbackEventHandler makeNewFallbackEventHandler(Context context) {   return new PhoneFallbackEventHandler(context);}}public class PhoneFallbackEventHandler implements FallbackEventHandler {    public boolean dispatchKeyEvent(KeyEvent event) {        final int action = event.getAction();        final int keyCode = event.getKeyCode();        if (action == KeyEvent.ACTION_DOWN) {            return onKeyDown(keyCode, event);        } else {            return onKeyUp(keyCode, event);        }    }        boolean onKeyDown(int keyCode, KeyEvent event) {        switch (keyCode) {            case KeyEvent.KEYCODE_CAMERA: {                if (event.getRepeatCount() == 0) {                } else if (event.isLongPress() && dispatcher.isTracking(event)) {                    //启动拍照程序                    Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);                    intent.putExtra(Intent.EXTRA_KEY_EVENT, event);                    mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT_OR_SELF,                            null, null, null, 0, null, null);                }                return true;            }        }        return false;    }

输入事件处理完成通知

client将事件处理完了,必须通知server已经完成对该事件的处理,否则server一直在等待事件完成而不能发送后面的事件。
private void finishInputEvent(QueuedInputEvent q) {        if (q.mReceiver != null) {            boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;                          // mReceiver是InputEventReciever            q.mReceiver.finishInputEvent(q.mEvent, handled);        }        recycleQueuedInputEvent(q);}public abstract class InputEventReceiver {    public final void finishInputEvent(InputEvent event, boolean handled) {        {            int index = mSeqMap.indexOfKey(event.getSequenceNumber());            if (index < 0) {            } else {                //又调回native层                nativeFinishInputEvent(mReceiverPtr, seq, handled);            }        }        event.recycleIfNeededAfterDispatch();    }}status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {    //告知server端client已经处理完成inputEvent    status_t status = mInputConsumer.sendFinishedSignal(seq, handled);    return status;}status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {    size_t seqChainCount = mSeqChains.size();    if (seqChainCount) {        uint32_t currentSeq = seq;        uint32_t chainSeqs[seqChainCount];        size_t chainIndex = 0;        for (size_t i = seqChainCount; i-- > 0; ) {             const SeqChain& seqChain = mSeqChains.itemAt(i);             if (seqChain.seq == currentSeq) {                 currentSeq = seqChain.chain;                 chainSeqs[chainIndex++] = currentSeq;                 mSeqChains.removeAt(i);             }        }        status_t status = OK;        while (!status && chainIndex-- > 0) {            status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled);        }    }    // Send finished signal for the last message in the batch.    return sendUnchainedFinishedSignal(seq, handled);}status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {    InputMessage msg;    msg.header.type = InputMessage::TYPE_FINISHED;    msg.body.finished.seq = seq;    msg.body.finished.handled = handled;    return mChannel->sendMessage(&msg);}//这个和server端发送事件过来一样的,只不过这次是client发送消息给serverstatus_t InputChannel::sendMessage(const InputMessage* msg) {    size_t msgLength = msg->size();    ssize_t nWrite;    do {        nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);    } while (nWrite == -1 && errno == EINTR);    return OK;}


/********************************

* 本文来自博客 “爱踢门”

* 转载请标明出处:http://blog.csdn.net/itleaks

******************************************/

更多相关文章

  1. 从Android 6.0源码的角度剖析View的事件分发机制
  2. 【Android】技术调研:用代码模拟屏幕点击、触摸事件
  3. android网络监听事件机制(kernel, c++, java)
  4. Android基于监听的事件处理机制
  5. Android 外接键盘的按键处理
  6. [置顶] Android开发:在onTouchEvent中处理任意时间的长按事件
  7. Android事件总线(四)源码解析otto

随机推荐

  1. MySQL企业版备份工具MEB
  2. 第三周
  3. MGR用哪个版本?5.7 vs 8.0
  4. MySQL字段默认值设置详解
  5. 我的第32个代码
  6. CentOS8配置本地yum
  7. 广州市翊腾通讯设备有限公司
  8. js的变量与常量、常用数据
  9. 推荐!10款最好用的Python IDE
  10. 详解linux如何搭建NTP北斗授时服务器