Android T 窗口点击过滤功能实现

背景

有些应用可能会存在透明窗口,或者界面异常导致当前页面无法触发点击事件,如果要从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

猜你喜欢

转载自blog.csdn.net/yimelancholy/article/details/130504875
今日推荐