IMS:Activity和View处理InputEvent
- 1、IMS服务处理
- 2、Activity的DecorView界面添加
- 3、Activity和View处理InputEvent
- 3.1 InputEventReceiver接收InputEvent
- 3.2 处理KeyEvent
- 3.3 处理MotionEvent
 
android12-release 
 
1、IMS服务处理
关键流程
EventHub -> InputReader -> InputDispatcher -> InputChannel/android_view_InputEventReceiver.cpp -> InputEventReceiver.java;查看如下相关文章和时序图
- InputReader线程获取输入事件-Android12
- InputDispatcher线程分发事件-Android12
- InputChannel通道建立-Android12
- InputChannel发送Input给App-Android12

2、Activity的DecorView界面添加
关键流程
wm.addView(decor,...) -> WindowManagerGlobal.java#addView -> ViewRootImpl.java#setView -> Session extends IWindowSession.Stub#addToDisplayAsUser -> WindowManagerService.java#addWindow,查看 Activity窗口的添加过程 了解,如下图查看,了解其中PhoneWindow.java是Android-specific Window,实际ViewRootImpl添加DecorView.java到WMS。
3、Activity和View处理InputEvent
3.1 InputEventReceiver接收InputEvent
添加窗口时,
ViewRootImpl.java中InputChannel / WindowInputEventReceiver建立联系;通过JNI调用,最终在WindowInputEventReceiver.java#onInputEvent通过InputStage责任链处理InputEvent,可参照1中时序图流程查看代码。
InputStage责任链:
SyntheticInputStage - ViewPostImeInputStage - NativePostImeInputStage - EarlyPostImeInputStage - ImeInputStage - ViewPreImeInputStage - NativePreImeInputStage,InputStage的各子类Input事件result = onProcess(q)处理,再判断是forward()向下传递,还是finish()结束。
- NativePreImeInputStage: 主要是为了将消息放到
NativeActivity中去处理。- ViewPreImeInputStage: 最后会调用Acitivity的所有view的onkeyPreIme方法,这样就给View在输入法处理key事件之前先得到消息。
- ImeInputStage:
onProcess(q)处理会调用InputMethodManager的dispatchInputEvent方法处理消息。- EarlyPostImeInputStage: 屏幕上有焦点的View会高亮显示,用来提示用户焦点所在。
- NativePostImeInputStage: 为了让IME处理完消息后能先于普通的Activity处理消息。
- ViewPostImeInputStage: Acitivity和view处理各种消息。
- SyntheticInputStage: 流水线的最后一级,经过层层过滤之后,到达这里的消息已经不多了,例如手机上的虚拟按键消息。
Activity和View的事件处理主要对应的InputStage是
ViewPostImeInputStage。
onProcess(q)中处理KeyEvent:processKeyEvent(q)
onProcess(q)中处理MotionEvent:processPointerEvent(q)、processTrackballEvent(q)、processGenericMotionEvent(q)
@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);
        }
    }
}
3.2 处理KeyEvent
处理顺序如下:
- DecorView传递给
Activity#dispatchKeyEvent处理
mFocused窗口的OnKeyListener监听,在处理其onKeyDown()、onKeyLongPress()、onKeyUp()、onKeyMultiple()方法
dispatchUnhandledKeyEvent()未拦截处理的KeyEvent发送给ViewGroup子View的OnUnhandledKeyEventListener监听- 在处理Activity中的
onKeyDown()、onKeyLongPress()、onKeyUp()、onKeyMultiple()方法- 未有任何窗口拦截处理,最后传递PhoneWindow的
onKeyDown()、onKeyUp()

 frameworks/base/core/java/com/android/internal/policy/DecorView.java
public boolean dispatchKeyEvent(KeyEvent event) {
    final int keyCode = event.getKeyCode();
    final int action = event.getAction();
    final boolean isDown = action == KeyEvent.ACTION_DOWN;
    if (isDown && (event.getRepeatCount() == 0)) {
        // First handle chording of panel key: if a panel key is held
        // but not released, try to execute a shortcut in it.
        if ((mWindow.mPanelChordingKey > 0) && (mWindow.mPanelChordingKey != keyCode)) {
            boolean handled = dispatchKeyShortcutEvent(event);
            if (handled) {
                return true;
            }
        }
        // If a panel is open, perform a shortcut on it without the
        // chorded panel key
        if ((mWindow.mPreparedPanel != null) && mWindow.mPreparedPanel.isOpen) {
            if (mWindow.performPanelShortcut(mWindow.mPreparedPanel, keyCode, event, 0)) {
                return true;
            }
        }
    }
    if (!mWindow.isDestroyed()) {
        final Window.Callback cb = mWindow.getCallback();
        final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event)
                : super.dispatchKeyEvent(event);
        if (handled) {
            return true;
        }
    }
    return isDown ? mWindow.onKeyDown(mFeatureId, event.getKeyCode(), event)
            : mWindow.onKeyUp(mFeatureId, event.getKeyCode(), event);
}
frameworks/base/core/java/android/view/KeyEvent.java
public final boolean dispatch(Callback receiver, DispatcherState state,
        Object target) {
    switch (mAction) {
        case ACTION_DOWN: {
            mFlags &= ~FLAG_START_TRACKING;
            if (DEBUG) Log.v(TAG, "Key down to " + target + " in " + state
                    + ": " + this);
            boolean res = receiver.onKeyDown(mKeyCode, this);
            if (state != null) {
                if (res && mRepeatCount == 0 && (mFlags&FLAG_START_TRACKING) != 0) {
                    if (DEBUG) Log.v(TAG, "  Start tracking!");
                    state.startTracking(this, target);
                } else if (isLongPress() && state.isTracking(this)) {
                    try {
                        if (receiver.onKeyLongPress(mKeyCode, this)) {
                            if (DEBUG) Log.v(TAG, "  Clear from long press!");
                            state.performedLongPress(this);
                            res = true;
                        }
                    } catch (AbstractMethodError e) {
                    }
                }
            }
            return res;
        }
        case ACTION_UP:
            if (DEBUG) Log.v(TAG, "Key up to " + target + " in " + state
                    + ": " + this);
            if (state != null) {
                state.handleUpEvent(this);
            }
            return receiver.onKeyUp(mKeyCode, this);
        case ACTION_MULTIPLE:
            final int count = mRepeatCount;
            final int code = mKeyCode;
            if (receiver.onKeyMultiple(code, count, this)) {
                return true;
            }
            if (code != KeyEvent.KEYCODE_UNKNOWN) {
                mAction = ACTION_DOWN;
                mRepeatCount = 0;
                boolean handled = receiver.onKeyDown(code, this);
                if (handled) {
                    mAction = ACTION_UP;
                    receiver.onKeyUp(code, this);
                }
                mAction = ACTION_MULTIPLE;
                mRepeatCount = count;
                return handled;
            }
            return false;
    }
    return false;
}
3.3 处理MotionEvent
待续





















