前言
"xx机型 进入待支付页面之后,【<】按钮点击没反应"
------ 这是测试同事最初的反馈。很多时候,我们会下意识把它当成:按钮被遮挡 / 没绑定监听 / 点击区域偏移 / 压力测试后状态异常。
但当我接手复测后,发现问题并不只是"一个按钮点不了",而是"整个上半屏(Dialog 之外的背景区域)完全没有触摸响应"。
这个"问题再界定"过程,直接决定了后续排查维度:从"控件级"转向"窗口输入命中级"。
最终根因是:一个看似纯视觉效果的窗口 Flag ------ FLAG_DIM_BEHIND
------ 在特定 ROM 上被策略层放大为"模态化处理",导致外部区域触摸事件被系统直接吞掉,没有分发进应用。下面详细展开全过程,并总结出可复用的输入排查方法论。
现象精确描述
场景:订单待支付页面,底部弹出一个自定义 Dialog(类似 Bottom Sheet 样式)。
- Dialog 内部:按钮、列表项点击全部正常
- 上半屏(Dialog 之外的可见 Activity 背景区域):完全无触摸响应(点击不触发埋点、也不触发全局触摸监控)
- 预期:点击背景区域应允许关闭弹层或继续交互(例如点击返回)
- 复现范围:特定 OEM(定制 ROM)出现;其他主流品牌正常
- 伴随现象:无异常崩溃日志;无明显 ANR;

分层排查策略总览
Android 输入链路(简化):
sql
物理触摸 → InputReader(读取设备事件)→ InputDispatcher(命中并派发)→ 应用 Window → DecorView / ViewGroup 分发 → 具体控件
目标:判断事件卡在哪一层。我们采用"自外向内"策略:先确认系统是否把事件派发给应用,再看应用内部是否消费/拦截。
事件是否进入应用窗口(系统派发层)
推荐 Perfetto 手指在本该响应的触摸区域,按下 滑动,抬起,重复多次,抓取 trace

- Outbound(俗称 oq):InputDispatcher 针对目标窗口的派发队列事件
发现 没有对应oq分配到 app的 Window
查看APP 对应window 属性
adb shell dumpsys window
xml
Window #9 Window{11b6259 u0 xxx.xxx.xxx.xx/xxx.xxx.xxx.xx.ui.runningorder.OrderActivity}:
mDisplayId=0 rootTaskId=462 mSession=Session{894b5d8 1199:u0a10560} mClient=android.os.BinderProxy@fde26a0
mOwnerUid=10560 showForAllUsers=false package=xxx.xxx.xxx.xx appop=NONE
mAttrs={(0,0)(fillxwrap) gr=BOTTOM CENTER_VERTICAL sim={adjust=pan} ty=APPLICATION fmt=TRANSPARENT wanim=0x7f120322 surfaceInsets=Rect(93, 93 - 93, 93) mSaturation=-2.0
// DIM_BEHIND 这个 FLAG : 猜测某机型 会把带 DIM_BEHIND 的窗口仍当成"模态"对待,外区域不下发触摸(或被直接丢弃)
fl=DIM_BEHIND NOT_TOUCH_MODAL SPLIT_TOUCH HARDWARE_ACCELERATED
...
Requested w=1080 h=918 mLayoutSeq=5622
Window #10 Window{344f9c2 u0 xxx.xxx.xxx.xx/xxx.xxx.xxx.xx.ui.runningorder.OrderActivity}:
mDisplayId=0 rootTaskId=462 mSession=Session{894b5d8 1199:u0a10560} mClient=android.os.BinderProxy@125460d
mOwnerUid=10560 showForAllUsers=false package=xxx.xxx.xxx.xx appop=NONE
mAttrs={(0,0)(fillxfill) sim={state=always_hidden adjust=resize forwardNavigation} layoutInDisplayCutoutMode=always ty=BASE_APPLICATION wanim=0x1030309 mSaturation=-2.0
fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
...
11b6259 (dialog 弹窗) ->
344f9c2 背景Activity ->
修改验证
java
// dialog window设置
...
//增加这一行: 手动清除 FLAG_DIM_BEHIND ,目前项目中有设置展开Dialog时,显示背景,所以这个属性,是不需要的
window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
window.setFlags(
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
);
...
验证
adb shell dumpsys window
xml
// 弹窗
Window #11 Window{682c4ff u0 xxx.xxx.xxx.xx/xxx.xxx.xxx.xx.ui.runningorder.OrderActivity}:
mDisplayId=0 rootTaskId=467 mSession=Session{f6119c4 1473:u0a10560} mClient=android.os.BinderProxy@72c741e
mOwnerUid=10560 showForAllUsers=false package=xxx.xxx.xxx.xx appop=NONE
mAttrs={(0,0)(fillxwrap) gr=BOTTOM CENTER_VERTICAL sim={adjust=pan} ty=APPLICATION fmt=TRANSPARENT wanim=0x7f120322 surfaceInsets=Rect(93, 93 - 93, 93) mSaturation=-2.0
// fl 已经没有那个属性了
fl=NOT_TOUCH_MODAL SPLIT_TOUCH HARDWARE_ACCELERATED
...
//背景层
Window #12 Window{acf7b41 u0 xxx.xxx.xxx.xx/xxx.xxx.xxx.xx.ui.runningorder.OrderActivity}:
mDisplayId=0 rootTaskId=467 mSession=Session{f6119c4 1473:u0a10560} mClient=android.os.BinderProxy@670f228
mOwnerUid=10560 showForAllUsers=false package=xxx.xxx.xxx.xx appop=NONE
mAttrs={(0,0)(fillxfill) sim={state=always_hidden adjust=resize forwardNavigation} layoutInDisplayCutoutMode=always ty=BASE_APPLICATION wanim=0x1030309 mSaturation=-2.0
fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
...
问题解决:尝试滑动,点击先前无响应的该区域,可以正常响应。
排查思路总结
- 先界定范围:单控件?一块区域?全局?(区域性 → 优先怀疑 Window 命中 / 策略)
- 抓 trace(Perfetto):
- 有 outbound(派发到目标窗口)吗?
- 无 outbound:
- 用 dumpsys window 看目标窗口 flags / type / Z 序
- 用 dumpsys input 看 FocusedWindow、touchableRegion
- 检查是否被其他高层窗口/遮罩/系统策略截走
- 有 outbound 但应用没反应:
- Activity.dispatchTouchEvent 是否触发?
- View 层是否被透明遮挡 / intercept / clickable=false
- 是否被 GestureDetector / OnTouchListener 提前消费