背景
有些应用可能会存在透明窗口,或者界面异常导致当前页面无法触发点击事件,如果要从input侧解决该问题,如何处理?
思路
1.通过dumpsys SurfaceFlinger
找到当前有问题的窗口
2.理清流程,找到过滤窗口相关代码
3.找到关键方法,并尝试修改
在InputDispatcher::findTouchedWindowTargetsLocked方法中有调用
sp<InputWindowHandle> newTouchedWindowHandle = findTouchedWindowAtLocked( displayId, x, y, isDown /*addOutsideTargets*/, true /*addPortalWindows*/);
用于查找对应窗口的 windowHandle
sp<WindowInfoHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x,
int32_t y, TouchState* touchState,
bool isStylus,
bool addOutsideTargets,
bool ignoreDragWindow) {
if (addOutsideTargets && touchState == nullptr) {
LOG_ALWAYS_FATAL("Must provide a valid touch state if adding outside targets");
}
// Traverse windows from front to back to find touched window.
//遍历所有窗口
const auto& windowHandles = getWindowHandlesLocked(displayId);
for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
if (ignoreDragWindow && haveSameToken(windowHandle, mDragState->dragWindow)) {
continue;
}
const WindowInfo& info = *windowHandle->getInfo();
//原生窗口过滤条件判断
if (!info.isSpy() && windowAcceptsTouchAt(info, displayId, x, y, isStylus)) {
//打印log
ALOGD("InputDispatcher findTouchedWindowAtLocked %s finded ",windowHandle->getName().c_str());
//我们需要找到对应窗口名称,例如我这里是找到带有“mysystemdialog”的窗口,可以通过dump SurfaceFlinger来查看当前你需要过滤的问题窗口
if (windowHandle->getName().find("mysystemdialog")!= std::string::npos){//注:npos可以表示string的结束位子,是string::type_size 类型的,也就是find()返回的类型。find函数在找不到指定值得情况下会返回string::npos
ALOGD("%s do not accept any motion ",windowHandle->getName().c_str());
//跳过当前窗口(即事件不派发到该窗口上)
continue;
}
//返回找到的窗口
return windowHandle;
}
if (addOutsideTargets &&
info.inputConfig.test(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH)) {
touchState->addOrUpdateWindow(windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE,
BitSet32(0));
}
}
return nullptr;
}
bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, int32_t x, int32_t y,
bool isStylus) {
const auto inputConfig = windowInfo.inputConfig;
if (windowInfo.displayId != displayId ||
inputConfig.test(WindowInfo::InputConfig::NOT_VISIBLE)) {
return false;
}
const bool windowCanInterceptTouch = isStylus && windowInfo.interceptsStylus();
if (inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) && !windowCanInterceptTouch) {
return false;
}
if (!windowInfo.touchableRegionContainsPoint(x, y)) {
return false;
}
ALOGD("windowAcceptsTouchAt return true");
return true;
}
4.验证修改
确认代码及其模块
代码路径:frameworks/native/services/inputflinger
编译模块:make inputflinger
生成包目录:
out/target/product/emulator_x86_64/system/lib/libinputflinger.so
out/target/product/emulator_x86_64/system/lib64/libinputflinger.so
push包验证
adb push libinputflinger.so system/lib
adb push libinputflinger.so system/lib64