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处理