Android之input app通信篇(二)客户端业务梳理

2022-01-27  本文已影响0人  锄禾豆
frameworks/base/core/java/android/view/ViewRootImpl.java
frameworks/base/core/java/android/view/inputmethod/InputMethodManager.java
代码:
7.1

ViewRootImpl
1.从“Andoid之input app通信篇(一)服务端业务梳理”已经了解到关键信息

mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
                            Looper.myLooper());

2.WindowInputEventReceiver怎么监听的并回调处理?
通过InputChannel承载的socket包裹在WindowInputEventReceiver里面,从而通过native回调回来
具体如下

1.WindowInputEventReceiver继承InputEventReceiver

    final class WindowInputEventReceiver extends InputEventReceiver {
        ···
        @Override
        public void onInputEvent(InputEvent event) {
            enqueueInputEvent(event, this, 0, true);
        }
        ···
    }

2.通过native回调dispatchInputEvent
3.对应到WindowInputEventReceiver的方法为onInputEvent
4.接下来的代码业务流程为:
onInputEvent --> enqueueInputEvent --> doProcessInputEvents --> deliverInputEvent
5.重点介绍deliverInputEvent
    private void deliverInputEvent(QueuedInputEvent q) {
        ···
        InputStage stage;
        if (q.shouldSendToSynthesizer()) {
            stage = mSyntheticInputStage;
        } else {
            //q.shouldSkipIme是否忽视输入法
            stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
        }

        if (stage != null) {
            stage.deliver(q);
        } else {
            finishInputEvent(q);
        }
    }
1)这里的stage为InputStage对象

2)q.shouldSkipIme()为按键或触摸事件的分水岭。 关注的一个点:event是按键或触摸。如果是按键event,则为false:
        public boolean shouldSkipIme() {
            if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
                return true;
            }
            return mEvent instanceof MotionEvent //MotionEvent是触摸事件
                    && (mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
                        || mEvent.isFromSource(InputDevice.SOURCE_ROTARY_ENCODER));
        }
        
3)stage调用deliver进行数据传递
触摸事件的stage=mFirstPostImeInputStage
按键事件的stage=mFirstInputStage

3-1)分析触摸事件

1)从EarlyPostImeInputStage开始,以链表的形式,包含下一个stage:NativePostImeInputStage,NativePostImeInputStage包含下一个stage:
ViewPostImeInputStage

2)EarlyPostImeInputStage.deliver
deliver --> onProcess --> apply

        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));
            }
        }

EarlyPostImeInputStage.onProcess 结果为FORWARD,这样通过apply --> forward --> onDeliverToNext
        
        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);
            }
        }
这样就来到mNext(NativePostImeInputStage)的执行流程

NativePostImeInputStage的执行结果(主要mInputQueue=null)仍是执行下一个mNext(ViewPostImeInputStage)
ViewPostImeInputStage
deliver --> onProcess --> apply
        @Override
        protected int onProcess(QueuedInputEvent q) {
            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);
                }
            }
        }
        
        private int processPointerEvent(QueuedInputEvent q) {
            ···
            //这里的eventTarget为DecorView
            final View eventTarget =
                    (event.isFromSource(InputDevice.SOURCE_MOUSE) && mCapturingView != null) ?
                            mCapturingView : mView;
            ···
            //到DecorView中处理dispatchPointerEvent
            boolean handled = eventTarget.dispatchPointerEvent(event);
            ···
            return handled ? FINISH_HANDLED : FORWARD;
        }

DecorView
    public final boolean dispatchPointerEvent(MotionEvent event) {
        if (event.isTouchEvent()) {//是触摸事件,走dispatchTouchEvent
            return dispatchTouchEvent(event);
        } else {
            return dispatchGenericMotionEvent(event);
        }
    }
    
    public boolean dispatchTouchEvent(MotionEvent ev) {
        //mWindow.getCallback就是Activity本身,因为它实现了接口Window.Callback
        //Activity.attach有:mWindow.setCallback(this);
        //DecorView的mFeatureId = -1
        final Window.Callback cb = mWindow.getCallback();
        //这样就来到Activity.dispatchTouchEvent
        return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
                ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
    }
    
Activiy.dispatchTouchEvent
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction();
        }
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
    }

触摸事件对应到Activity中为dispatchTouchEvent

3-2)分析按键事件

1.从NativePreImeInputStage开始分析,以链表的形式,连接的如下
NativePreImeInputStage --next-> ViewPreImeInputStage --next-> ImeInputStage --next-> EarlyPostImeInputStage --next-> NativePostImeInputStage --next-> ViewPostImeInputStage --next-> SyntheticInputStage

代码流程:deliver --> onProcess --> apply --> forward --> onDeliverToNext --> deliver

NativePreImeInputStage.onProcess --··--> ViewPreImeInputStage.onProcess --··--> ImeInputStage.onProcess

ImeInputStage.onProcess
    final class ImeInputStage extends AsyncInputStage
            implements InputMethodManager.FinishedInputEventCallback {
        ···
        @Override
        protected int onProcess(QueuedInputEvent q) {
            if (mLastWasImTarget && !isInLocalFocusMode()) {
                InputMethodManager imm = InputMethodManager.peekInstance();
                if (imm != null) {
                    final InputEvent event = q.mEvent;
                    //发送到InputMethodManager中,回到为FinishedInputEventCallback
                    //结果为DEFER,插入队列中,等待回调到onFinishedInputEvent才使用
                    //流程 app --> ime --> app
                    int result = imm.dispatchInputEvent(event, q, this, mHandler);
                    if (result == InputMethodManager.DISPATCH_HANDLED) {
                        return FINISH_HANDLED;
                    } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
                        // The IME could not handle it, so skip along to the next InputStage
                        return FORWARD;
                    } else {
                        return DEFER; // callback will be invoked later
                    }
                }
            }
            return FORWARD;
        }

        @Override
        public void onFinishedInputEvent(Object token, boolean handled) {
            QueuedInputEvent q = (QueuedInputEvent)token;
            if (handled) {
                finish(q, true);
                return;
            }
            forward(q);
        }
    }
    这里我们先关注回调后的业务处理情况,回调过程的实现我们先不关注
EarlyPostImeInputStage.onProcess --> NativePostImeInputStage.onProcess --> ViewPostImeInputStage.onProcess
ViewPostImeInputStage.onProcess
    final class ViewPostImeInputStage extends InputStage {
        ···
        @Override
        protected int onProcess(QueuedInputEvent q) {
            if (q.mEvent instanceof KeyEvent) {
                return processKeyEvent(q);
            } else {
                ···
            }
        }
        ···
        private int processKeyEvent(QueuedInputEvent q) {
            final KeyEvent event = (KeyEvent)q.mEvent;

            // Deliver the key to the view hierarchy.
            // 到DecorView中处理dispatchKeyEvent事件
            if (mView.dispatchKeyEvent(event)) {
                return FINISH_HANDLED;
            }
            ···
            return FORWARD;
        }

DecorView.dispatchKkeyEvent
    public boolean dispatchKeyEvent(KeyEvent event) {
        ···
        if (!mWindow.isDestroyed()) {
            final Window.Callback cb = mWindow.getCallback();
            //cb为Activity对象,这里就关联到Activity.dispatchKeyEvent
            final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event)
                    : super.dispatchKeyEvent(event);
            if (handled) {
                return true;
            }
        }

        //如果上面没有拦截,则会调用PhoneWindow.onKeyDown/onKeyUp
        //这里面有音量加减键的触发等
        return isDown ? mWindow.onKeyDown(mFeatureId, event.getKeyCode(), event)
                : mWindow.onKeyUp(mFeatureId, event.getKeyCode(), event);
    }

(1)按键事件对应到Activity.dispatchKeyEvent
(2)如果没有分发成功,则调用PhoneWindow.onKeyDown/onKeyUp事件,这里的事件包含了音量的分发

3-3)IME -- app的回调搭建分析
代码分析:

InputMethodManager imm = InputMethodManager.peekInstance();
int result = imm.dispatchInputEvent(event, q, this, mHandler);

InputMethodManager.dispatchInputEvent
    public int dispatchInputEvent(InputEvent event, Object token,
            FinishedInputEventCallback callback, Handler handler) {
        synchronized (mH) {
            if (mCurMethod != null) {
                ···
                //将数据放在PendingEvent中
                PendingEvent p = obtainPendingEventLocked(
                        event, token, mCurId, callback, handler);
                if (mMainLooper.isCurrentThread()) {
                    // Already running on the IMM thread so we can send the event immediately.
                    //将p通过sendInputEventOnMainLooperLocked发送出去
                    return sendInputEventOnMainLooperLocked(p);
                }
                ···
            }
        }
        return DISPATCH_NOT_HANDLED;
    }

    int sendInputEventOnMainLooperLocked(PendingEvent p) {
        if (mCurChannel != null) {
            if (mCurSender == null) {
                //创建socket通信的处理器ImeInputEventSender
                mCurSender = new ImeInputEventSender(mCurChannel, mH.getLooper());
            }

            final InputEvent event = p.mEvent;
            final int seq = event.getSequenceNumber();
            if (mCurSender.sendInputEvent(seq, event)) {//发送数据到socket服务端
                mPendingEvents.put(seq, p);//将数据保存在数组中
                Trace.traceCounter(Trace.TRACE_TAG_INPUT, PENDING_EVENT_COUNTER,
                        mPendingEvents.size());

                //超时机制监听
                Message msg = mH.obtainMessage(MSG_TIMEOUT_INPUT_EVENT, p);
                msg.setAsynchronous(true);
                mH.sendMessageDelayed(msg, INPUT_METHOD_NOT_RESPONDING_TIMEOUT);
                return DISPATCH_IN_PROGRESS;
            }

            Log.w(TAG, "Unable to send input event to IME: "
                    + mCurId + " dropping: " + event);
        }
        return DISPATCH_NOT_HANDLED;
    }
    

InputMethodManager.ImeInputEventSender接收服务端socket发送的数据
    private final class ImeInputEventSender extends InputEventSender {
        public ImeInputEventSender(InputChannel inputChannel, Looper looper) {
            super(inputChannel, looper);
        }

        //native的回调函数
        @Override
        public void onInputEventFinished(int seq, boolean handled) {
            finishedInputEvent(seq, handled, false);
        }
    }
    
    void finishedInputEvent(int seq, boolean handled, boolean timeout) {
        final PendingEvent p;
        synchronized (mH) {
            int index = mPendingEvents.indexOfKey(seq);
            if (index < 0) {
                return; // spurious, event already finished or timed out
            }

            //从数据获取保存在数组中的PendingEvent对象
            p = mPendingEvents.valueAt(index);
            mPendingEvents.removeAt(index);
            Trace.traceCounter(Trace.TRACE_TAG_INPUT, PENDING_EVENT_COUNTER, mPendingEvents.size());

            ···
        }

        //调用PendingEvent的回调函数
        invokeFinishedInputEventCallback(p, handled);
    }
    
    void invokeFinishedInputEventCallback(PendingEvent p, boolean handled) {
        p.mHandled = handled;
        if (p.mHandler.getLooper().isCurrentThread()) {
            //执行run
            p.run();
        } else {
            ···
        }
    }
    
    private final class PendingEvent implements Runnable {
        ···
        @Override
        public void run() {
            //执行回调方法,就回到了app
            mCallback.onFinishedInputEvent(mToken, mHandled);
            ···
        }
    }

总结

1.触摸事件对应到Activity中为dispatchTouchEvent
2.按键事件对应到Activity.dispatchKeyEvent
3.触摸事件和按键事件的业务分发流程有差异,但根源都是WindowInputEventReceiver处理
上一篇下一篇

猜你喜欢

热点阅读