在处理触摸事件是,经常会发现触摸事件没有反映。
这里通过增加Log的方式,实践地进行触摸事件的跟踪
参考下边的链接,可以知道,窗口在Android中,以Window类形式出现,系统通过inputFlinger将触摸事件发送的Window中。
所以首先在inputFlinger中增加对按下事件处理的Log。
inputFlinger中,当按下时,会开始查找合适的窗口。当然,只能由一个Window实例进行处理(从代码看是如此)。之后的滑动到手指离开屏幕之前,都是这个Widnow。当然肯定会有例外情况,这里未具体看。
frameworks/native/services/inputflinger/InputDispacher.cpp
int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
const MotionEntry* entry, Vector& inputTargets, nsecs_t* nextWakeupTime,
bool* outConflictingPointerActions) {
... ...
if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
/* Case 1: New splittable pointer going down, or need target for hover or scroll. */
... ...
// Traverse windows from front to back to find touched window and outside targets.
size_t numWindows = mWindowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
... ...
}
// 这里,增加Log,打印出来点击按下时,处理事件的窗口。
if (newTouchedWindowHandle != NULL) {
ALOGI("Vigi Event Process Window is %s", newTouchedWindowHandle->getName().c_str());
}
}
编译/system/lib64/libinputflinger.so 执行后,打印的Log如下:
可以看到在桌面,通知栏,底部导航栏上的点下Log信息。通过这个,可以分析框架点击事件,是否分发给了对应的Window。
01-13 11:36:06.733: I/InputDispatcher(922): Vigi Event Process Window is Window{c578ed1 u0 com.android.launcher3/com.android.launcher3.Launcher}
01-13 11:36:10.724: I/InputDispatcher(922): Vigi Event Process Window is Window{e7bae42 u0 StatusBar}
01-13 11:36:12.692: I/InputDispatcher(922): Vigi Event Process Window is Window{3658693 u0 NavigationBar}
如果上边只是说明了inputflinger将事件通过通道发送了出去,那么下边位置增加Log打印,就可以知道应用中是否接收到了事件
在frameworks/base/core/java/android/view/ViewRootImpl.java文件中,
final class WindowInputEventReceiver extends InputEventReceiver {
private InputChannel mInputChannel;
public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
mInputChannel = inputChannel;
}
@Override
public void onInputEvent(InputEvent event, int displayId) {
/// M: record current key event and motion event to dump input event info for
/// ANR analysis. {
ViewDebugManager.getInstance().debugInputEventStart(event);
/// }
// 这里增加Log打印,输入当前通道的名称,就可以知道是否是自己关心的应用了
android.util.Log.d("vigi", "Channel is " + (mInputChannel != null ? mInputChannel.getName() : "NULL"));
enqueueInputEvent(event, this, 0, true);
}
@Override
public void onBatchedInputEventPending() {
if (mUnbufferedInputDispatch) {
super.onBatchedInputEventPending();
} else {
scheduleConsumeBatchedInput();
}
}
@Override
public void dispose() {
mInputChannel = null;
unscheduleConsumeBatchedInput();
super.dispose();
}
}
输出的结果如下:
我写了三个例子,
01-13 15:19:23.511: D/vigi(1435): Channel is a5d9e1 NavigationBar (client)
01-13 15:19:23.511: D/vigi(1435): Channel is 3f21987 StatusBar (client)
01-13 15:19:23.510: D/vigi(4159): Channel is e64dc99 cn.dida.wordgames2/cn.dida.wordgames2.articalgame.ArticalMainActivity (client)
如果上边的事件正确传递,会进入Activity的dispatchTouchEvent中。
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.d("vigi", "dispatchTouchEvent ev = " + ev);
return super.dispatchTouchEvent(ev);
}
后边事件会分发给具体的View,所以在需要分析,就是纯的界面相关的流程了。
参考:
https://www.jianshu.com/p/f05d6b05ba17