于都建设银行网站招聘,怎么利用QQ空间给网站做排名,ip营销,交互设计网站有哪些最近在做语音全局控制Android系统功能#xff0c;通过集成第三方语音识别sdk得到相关控制指令#xff0c;然后将指令通过进程间通信传递给当前应用并作出响应。有很多通用指令#xff0c;比如播放/暂停#xff0c;Android系统本身就有全局控制指令#xff1a;KeyEvent.KEY…最近在做语音全局控制Android系统功能通过集成第三方语音识别sdk得到相关控制指令然后将指令通过进程间通信传递给当前应用并作出响应。有很多通用指令比如播放/暂停Android系统本身就有全局控制指令KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE只需模拟发送该遥控键值即可如下Instrumentation inst new Instrumentation();// 调用inst对象的按键模拟方法inst.sendKeyDownUpSync(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);其他控制指令也可以类似处理模拟发送一个遥控键值然后在目标应用中通过监听键值事件进行功能处理即可Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {switch (keyCode){case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:break;}return super.onKeyDown(keyCode, event);}正常这个逻辑是没问题的但实际使用中发现只要是通过语音指令模拟发送的键值目标应用都无法监听到而通过遥控器直接操作或者adb命令操作都没问题这个就很奇怪了后面通过log分析看到当前KeyEvent接收的应用包名是上面集成的第三方语音服务的这就清楚了语音交互的时候有个弹窗遥控事件被弹窗拦截了。解决办法有个方案1.延时发送模拟键值等弹窗消失后再发送2.通过发送广播方式进行通信目标应用接收广播后处理。下面给出一份从应用侧到系统侧的「Android 焦点窗口变化」完整链路梳理覆盖触发时机、WMS/SurfaceFlinger/InputDispatcher 三大核心模块的协作过程并补充常被忽略的细节多屏、IME、无焦点 ANR 等。
一、名词澄清
• 焦点窗口Focused WindowInputDispatcher 在派发 KeyEvent 时唯一的目标窗口与 View 体系中“焦点 View”不是一个层次的概念。
• TopFocusedDisplayRootWindowContainer.mTopFocusedDisplayId决定了当 KeyEvent 未指定屏幕时由哪块屏接收。
二、触发场景窗口增删/可见性变化relayoutWindow()、removeWindow()、finishDrawingWindow()。切换 ActivityDialog 弹出。多屏切换setFocusedDisplay()。强制清除焦点turnScreenOff(), 锁屏。输入法窗口显隐InputMethodManagerService 调用 WMS.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES)。
三、核心流程一次典型的焦点切换阶段 1WMS — “选拔”焦点窗口
① 入口WMS.updateFocusedWindowLocked(mode, updateInputWindows)
② RootWindowContainer 遍历 DisplayContent调用 dc.updateFocusedWindowLocked()
③ DisplayContent.findFocusedWindowIfNeeded() 按 Z-order 自上而下过滤
• 可见、非悬浮错误类型、非 SYSTEM_OVERLAY、不被遮挡
• 若存在焦点 ActivitymAppToken.containsFocusedWindow则返回其主窗口
• 若无 Activity 状态正常则选顶部可聚焦窗口
④ 若 newFocusmCurrentFocus直接返回否则把 mCurrentFocus 更新为 newFocus 并记录日志。
⑤ getInputMonitor().setInputFocusLw(newFocus, updateInputWindows) 把结果同步给 InputDispatcher。
⑥ 其他副作用
• 调整 IME target、toast 超时、Task 阴影、SystemUI 可见性。阶段 2SurfaceFlinger — 仅做事务封装
• InputMonitor 通过 SurfaceFlinger 的 createInputWindow/Transaction 把 InputWindowHandle 传给 InputDispatcher。
• 新版本使用 gui::WindowInfosUpdate 批量传输减少 Binder 次数。阶段 3InputDispatcher — “选举结果”生效
① onWindowInfosChanged() → setInputWindowsLocked() 更新 mWindowHandlesByDisplay。
② setFocusedWindow()
• FocusResolver.updateFocusedWindow() 返回 FocusChanges{oldFocus, newFocus, displayId, reason}。
• onFocusChangedLocked()
- 若 oldFocus 存在向旧窗口发送 CANCEL_NON_POINTER_EVENTS并 enqueueFocusEvent(oldToken, false)。
- 向新窗口 enqueueFocusEvent(newToken, true)。
• mLooper-wake() 触发下一次 pollOnce立即派发 FocusEvent。阶段 4应用进程 — 收到焦点变更
• Java ViewRootImpl 收到 FocusEvent → DecorView.onWindowFocusChanged() → Activity.onWindowFocusChanged() → 开发者可重写。
• UnityPlayer、FlutterEngine 等 Native 引擎通过监听 windowFocusChanged 决定是否继续渲染或暂停音频。
四、无焦点 ANR 的形成
• InputDispatcher 在派发 KeyEvent 时若 mFocusedWindowTokenByDisplay[displayId] 为空且 5 s 内仍无窗口获得焦点触发 “Reason: Waiting because no window has focus …” ANR。
五、多屏场景补充
• 每块 DisplayContent 维护独立的 mCurrentFocus。
• RootWindowContainer.updateTopFocusedDisplay() 在每次焦点窗口变化后重新计算 mTopFocusedDisplayId
– 若某屏有 Activity 含有顶部可见窗口 → 选该屏
– 否则选默认内屏。
六、关键类/文件速查
WMSWindowManagerService.java、RootWindowContainer.java、DisplayContent.java、InputMonitor.java
InputInputDispatcher.cpp、FocusResolver.cpp、InputWindowInfo.h
SurfaceFlingerSurfaceFlinger.cppcreateInputWindow、Transaction
七、一句话总结
“焦点窗口”的更新是一场跨进程接力
WMS 负责“选拔” → SurfaceFlinger 负责“运输” → InputDispatcher 负责“生效”
最终让正确的窗口在 KeyEvent 到达时“独占”输入事件。