前言

继续跟MediaSession,按键的分发。续接上文《简单跟一下MediaSession源码3》,对应MediaButton的监听我们已经跟到了PhoneFallbackEventHandler.java的dispatchKeyEvent()中。

今天继续跟,看看哪里调用dispatchKeyEvent()。

我这只关注down事件哈

正文

回到PhoneFallbackEventHandler.dispatchKeyEvent()

PhoneFallbackEventHandler.java

frameworks\base\core\java\com\android\internal\policy\PhoneFallbackEventHandler.java

PhoneFallbackEventHandler实现FallbackEventHandler接口,并重写了。

public void setView(View v);
public void preDispatchKeyEvent(KeyEvent event);
public boolean dispatchKeyEvent(KeyEvent event);
dispatchKeyEvent()
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);
    }
}

返回true表示被消费了。

查询到调用dispatchKeyEvent()是在ViewRootImpl.java的processKeyEvent()中调用的。

ViewRootImpl.java

ViewRootImpl 是 View 的最高层级,是所有 View 的根。processKeyEvent()是看谁需要消费event事件。

当前我们只关注上一曲事件哈,其他的后续在看。

processKeyEvent()
private int processKeyEvent(QueuedInputEvent q) {
    //下面都是看是否需要消费
    final KeyEvent event = (KeyEvent)q.mEvent;
    if (mUnhandledKeyManager.preViewDispatch(event)) {
        return FINISH_HANDLED;
    }
    if (mView.dispatchKeyEvent(event)) {
        return FINISH_HANDLED;
    }
    if (shouldDropInputEvent(q)) {
        return FINISH_NOT_HANDLED;
    }
    if (mUnhandledKeyManager.dispatch(mView, event)) {
        return FINISH_HANDLED;
    }
    //略
    //调用mFallbackEventHandler查看是否需要消费
    //这里消费了,因为符合条件。
    if (mFallbackEventHandler.dispatchKeyEvent(event)) {
        return FINISH_HANDLED;
    }
    //略,后续的后续有机会分析,暂时不走下面
    return FORWARD;
}

processKeyEvent()又在ViewPostImeInputStage.onProcess()中调佣的。

ViewPostImeInputStage.onProcess()

ViewPostImeInputStage是继承InputStage抽象类。

@Override
protected int onProcess(QueuedInputEvent q) {
    //当前发送的event是KeyEvent的实例
    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);
        }
    }
}

onProcess()是在其父类中InputStage.deliver()中调用的,ViewPostImeInputStage没有重写,因此调用时走起父类。

InputStage.deliver()

进入InputStage抽象类

public final void deliver(QueuedInputEvent q) {
    ViewDebugConfig.getInstance().debugInputStageDeliverd(this,
            System.currentTimeMillis());
    //看一下消费
    if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
        forward(q);
    } else if (shouldDropInputEvent(q)) {
        finish(q, false);
    } else {
        //走这里,我们这是88键值且为down事件
        traceEvent(q, Trace.TRACE_TAG_VIEW);
        final int result;
        try {
            //进入onProcess()处理流程,这里result返回值为0
            result = onProcess(q);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
        // 接着进入
        apply(q, result);
    }
}

这里有两个重点:

  1. onProcess(),ViewPostImeInputStage重写了,进入ViewPostImeInputStage实现类中,也就是上面我们走的流程。

  2. apply(),ViewPostImeInputStage没有重新,进入InputStage类中。

下面看一下InputStage.apply()。

注意,上面result返回的是0,也就是FORWARD,具体看上面processKeyEvent()返回值。

InputStage.apply()
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);
    }
}

InputStage中的forward()方法也没有被ViewPostImeInputStage重写,因此看InputStage。

InputStage.forward()
protected void forward(QueuedInputEvent q) {
    onDeliverToNext(q);
}

这里调用了onDeliverToNext()。

这里要注意,InputStage是抽象类,其子类好几个。这里打断一下,我看看看其子类的初始化哈。

setView()

InputStage子类初始化是在setView()中,

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
        int userId) {
    synchronized (this) {
        if (mView == null) {
            mView = view;
            //略
            //初始化InputStage子类
            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;
            
            //略
        }
    }
}

InputStage子类很多,然后我们会发现ViewPostImeInputStage对象会传入下一个InputStage子类对象中,并赋值给InputStage中定义的变量mNext中。

有点像栈,初始化时先进,退出时最后出。

所以后面onDeliverToNext()中判断mNext是否为null,不为null就事件继续传递。

有点乱,哈哈。

因此,这里要明白如果子类重写了onDeliverToNext(),就走子类,如果没有就走父类。如果mNext最后为null,就走finishInputEvent()。

InputStage.onDeliverToNext()

第一个SyntheticInputStage传入的mNext为null,其他的子类传入mNext不为null。

protected void onDeliverToNext(QueuedInputEvent q) {
    //如果mNext不为null,走这里
    if (mNext != null) {
        mNext.deliver(q);
    } else {
        finishInputEvent(q);
    }
}
deliverInputEvent()

回到上面,看一下哪里调用deliver()的,最后发现deliverInputEvent()调用的。

private void deliverInputEvent(QueuedInputEvent q) {
    //略
    try {
        //略
        InputStage stage;
        if (q.shouldSendToSynthesizer()) {
            stage = mSyntheticInputStage;
        } else {
            stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
        }
        //这里的mEvent是KeyEvent对象,我们这里只看发送的上一曲88事件
        if (q.mEvent instanceof KeyEvent) {
            try {
                mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }
        }
        //不为null
        if (stage != null) {
            //处理窗口焦点变化
            handleWindowFocusChanged();
            //调用了deliver()
            stage.deliver(q);
        } else {
            finishInputEvent(q);
        }
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    }
}

这个方法是在doProcessInputEvents()中调用的。

doProcessInputEvents()
void doProcessInputEvents() {
    while (mPendingInputEventHead != null) {
        //队列,所有先赋值,然后取下一个
        QueuedInputEvent q = mPendingInputEventHead;
        //取下一个
        mPendingInputEventHead = q.mNext;
        //如果为null,把尾置为null
        if (mPendingInputEventHead == null) {
            mPendingInputEventTail = null;
        }
        q.mNext = null;
        //计数器减去一
        mPendingInputEventCount -= 1;
        mViewFrameInfo.setInputEvent(mInputEventAssigner.processEvent(q.mEvent));
        //调用deliverInputEvent处理队列中的QueuedInputEvent
        deliverInputEvent(q);
    }
    if (mProcessInputEventsScheduled) {
        mProcessInputEventsScheduled = false;
        mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
    }
}

这里用了循环处理队列中存在的InputEvent事件。

enqueueInputEvent()

添加事件到队列中,然后判断是否需要立即处理该事件。

@UnsupportedAppUsage
void enqueueInputEvent(InputEvent event,
        InputEventReceiver receiver, int flags, boolean processImmediately) {
    //把事件添加到QueuedInputEvent
    QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
    //看是否MotionEvent类型事件
    if (event instanceof MotionEvent) {
        MotionEvent me = (MotionEvent) event;
        if (me.getAction() == MotionEvent.ACTION_CANCEL) {
            EventLog.writeEvent(EventLogTags.VIEW_ENQUEUE_INPUT_EVENT, "Motion - Cancel",
                    getTitle().toString());
        }
    } else if (event instanceof KeyEvent) {
        //KeyEvent事件
        KeyEvent ke = (KeyEvent) event;
    }
    QueuedInputEvent last = mPendingInputEventTail;
    //如果队列尾为null,也就是里面没有数据,赋值
    if (last == null) {
        //这里赋值mPendingInputEventHead和mPendingInputEventTail
        mPendingInputEventHead = q;
        mPendingInputEventTail = q;
    } else {
        last.mNext = q;
        mPendingInputEventTail = q;
    }
    //事件计数器+1
    mPendingInputEventCount += 1;
    //传入的是true,立即处理
    if (processImmediately) {
        doProcessInputEvents();
    } else {
        scheduleProcessInputEvents();
    }
}

上面方便是在onInputEvent()调用的。

WindowInputEventReceiver.onInputEvent()
@Override
public void onInputEvent(InputEvent event) {
    ViewDebugConfig.getInstance().debugInputEventStart(event);
    List<InputEvent> processedEvents;
    try {
        //方法中有对事件类型判断,如果不是MotionEvent,一定返回null
        //我们这里是Keyevent事件
        processedEvents =
            mInputCompatProcessor.processInputEventForCompatibility(event);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    }
    //processedEvents为null
    if (processedEvents != null) {
        //略
    } else {
        //dropIfNeeded()返回的是false,反一下就为true,调用enqueueInputEvent
        if (!dropIfNeeded(event)) {
            enqueueInputEvent(event, this, 0, true);
        } else {
            finishInputEvent(event, true);
        }
    }
}

这里WindowInputEventReceiver很重要,是ViewRootImpl接受Event事件的分发地方。这里暂时不介绍,有兴趣可以看参考文。

到此,发送的上一曲键值88就从这开始分发的。

后续专门介绍WindowInputEventReceiver。

参考文章

  1. Android InputEventReceiver事件接收流程分析

  2. 当你触摸屏幕时手机都干了什么?你必须知道的Android事件传递

相关文章

暂无评论

none
暂无评论...