Android怎么开发Input系统触摸事件分发(android,input,开发技术)

时间:2024-05-02 11:53:15 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

    Android%E6%80%8E%E4%B9%88%E5%BC%80%E5%8F%91Input%E7%B3%BB%E7%BB%9F%E8%A7%A6%E6%91%B8%E4%BA%8B%E4%BB%B6%E5%88%86%E5%8F%91

Input系统: InputReader 处理触摸事件 分析了 InputReader 对触摸事件的处理流程,最终的结果是把触摸事件包装成 NotifyMotionArgs,然后分发给下一环。根据 Input系统: InputManagerService的创建与启动 可知,下一环是 InputClassifier。然而系统目前并不支持 InputClassifier 的功能,因此事件会被直接发送到 InputDispatcher。

Input系统: 按键事件分发 分析了按键事件的分发流程,虽然分析的目标是按键事件,但是也从整体上,描绘了事件分发的框架。

InputDispatcher 收到触摸事件后的处理流程,与收到按键事件的处理流程非常相似

对触摸事件进行截断策略查询。

把触摸事件加入 InputDispatcher 收件箱,然后唤醒线程处理触摸事件。

一个触摸事件,必须满足下面三种情况,才执行截断策略

触摸事件是受信任的。来自输入设备的触摸事件都是受信任的。

触摸事件是非注入的。monkey 的原理就是注入触摸事件,因此它的事件是不需要经过截断策略处理的。

设备处于非交互状态。一般来说,非交互状态指的就是显示屏处于灭屏状态。

另外还需要关注的是,事件在什么时候是不需要经过截断策略,有两种情况

对于受信任且非注入的触摸事件,如果设备处于交互状态,直接发送给用户。 也就是说,如果显示屏处于亮屏状态,输入设备产生的触摸事件一定会发送给窗口。

对于不受信任,或者注入的触摸事件,如果设备处于交互状态,也是直接发送给用户。也就是说,如果显示屏处于亮屏状态,monkey 注入的触摸事件,也是直接发送给窗口的。

最后还要注意一件事,如果一个触摸事件是不受信任的事件,或者是注入事件,当设备处于非交互状态下(通常指灭屏),那么它不经过截断策略,也不会发送给用户,也就是会被丢弃。

在实际工作中处理的触摸事件,通常都是来自输入设备,它肯定是受信任的,而且非注入的,因此它只有在设备处于非交互状态下(一般指灭屏)下,非会执行截断策略,而如果设备处于交互状态(通常指亮屏),会被直接分发给窗口。

现在来看下截断策略的具体实现

截断策略是否截断触摸事件,取决于策略的返回值,有两种情况

返回 0,表示截断触摸事件。

返回 ACTION_PASS_TO_USER ,表示不截断触摸事件,也就是把触摸事件分发给用户/窗口。

下面列举触摸事件截断与否的情况,但是要注意一个前提,设备处于非交互状态(一般就是指灭屏状态)

事件会被传递给用户,也就是不截断,情况如下

有锁屏,并且显示屏处于非 off 状态。注意,非 off 状态,并不是表示屏幕处于 on(亮屏) 状态,也可能是 doze 状态(屏幕处于低电量状态),doze 状态屏幕也是黑的。

梦境状态。因为梦境状态下会运行 doze 组件。

事件被截断,情况如下

策略标志位包含 FLAG_WAKE ,它会导致屏幕被唤醒,因此需要截断触摸事件。FLAG_WAKE 一般来自于输入设备的配置文件。

没有锁屏,没有梦境,也没有 FLAG_WAKE,默认就会截断。

从上面的分析可以总结出了两条结论

如果系统有组件在运行,例如,锁屏、doze组件,那么触摸事件需要分发到这些组件,因此不会被截断。

如果没有组件运行,触摸事件都会被截断。触摸事件由于需要唤醒屏幕,而导致被截断,只是其中一个特例。

由 Input系统: InputManagerService的创建与启动 可知,InputDispatcher 通过线程循环来处理收件箱中的事件,而且一次循环只能处理一个事件

一次线程循环处理触摸事件的过程如下

分发一个触摸事件。

当事件分发给窗口后,会计算一个窗口反馈的超时时间,利用这个时间,计算线程下次唤醒的时间点。

利用上一步计算出的线程唤醒的时间点,计算出线程最终需要休眠多长时间。当线程被唤醒后,会检查接收触摸时间的窗口,是否反馈超时,如果超时,会引发 ANR。

现在来看看如何分发一个触摸事件

Input系统: 按键事件分发 已经分析过 InputDispatcher 的线程循环。而对于触摸事件,是通过 InputDispatcher::dispatchMotionLocked() 进行分发

一个触摸事件的分发过程,可以大致总结为以下几个过程

如果有原因表明触摸事件需要被丢弃,那么触摸事件不会走后面的分发流程,即被丢弃。

通常触摸事件是发送给窗口的,因此需要为触摸事件寻找触摸窗口。窗口最终被保存到 inputTargets 中。

inputTargets 保存触摸窗口后,还要保存 global monitor 窗口。例如开发者选项中的 Show taps 和 Pointer location,就是利用这个窗口实现的。

启动分发循环,把触摸事件分发给 inputTargets 保存的窗口。 由于 Input系统: 按键事件分发 已经分发过这个过程,本文不再分析。

为触摸事件寻找触摸窗口的过程,极其复杂。虽然这段代码被我省略了很多过程,但是我估计读者也会看得头晕。

对于 DOWN 事件

根据 x,y 坐标寻找触摸的窗口。

获取所有的 gesture monitor 窗口 。

把触摸窗口保存到 tempTouchState 中。

把所有的 gesture monitor 窗口保存到 tempTouchState 中。

为 tempTouchState 保存所有窗口,创建 InputTarget 对象,并保存到参数 inputTargets 中。

使用 mTouchStatesByDisplay 缓存 tempTouchState。

gesture monitor 是为了实现手势功能而添加的一个窗口。什么是手势功能? 例如在屏幕的左边/右边,向屏幕中央滑动,会触发返回手势。这个手势功能用来替代导航键。在下一篇文章中,我会剖析这个手势功能的原理。

对于非 DOWN 事件,一般为 MOVE, UP 事件

获取 DOWN 事件缓存的 tempTouchState。 因为 tempTouchState 保存了处理 DOWN 事件的触摸窗口和 gesture monitor,非 DOWN 事件,也会发送给这些窗口。

重复 DOWN 事件的第5步。

当分析的代码量很大的时候,我们需要有一个整体的观念。为触摸事件寻找触摸窗口,最终的结果就是把找到的窗口保存到参数 inputTargets 中,后面会把事件分发给 inputTargets 保存的窗口。

这里涉及一个 portal window 的概念,由于我没有找到具体使用的地方,我大致猜测它的意思就是,设备外接一个屏幕,然后在主屏幕上显示一个窗口来操作这个外接屏幕。后面的分析,我将略过 portal window 的部分。当然,触摸掌握了触摸事件的分发流程,以后遇到了 portal window 的事情,再来分析,应该没问题的。

寻找触摸点所在的窗口,其实就是从上到下遍历所有窗口,然后找到满足条件的窗口。

窗口首先要满足前置条件

窗口要在指定屏幕上。

窗口要可见。

窗口要可触摸。

满足了所有的前置条件后,只要满足以下任意一个条件,那么就找到了触摸点所在的窗口

是触摸模型的窗口: 可获取焦点,并且不允许窗口之外的触摸事件发送到它后面的窗口。

触摸点的 x,y 坐标落在窗口坐标系中。

对于触摸事件,无论是触摸窗口,还是 gesture monitor,都会被转化为 InputTarget,然后保存到参数 inputTargets 中。当后面启动分发循环后,触摸事件就会发送到 inputTargets 保存的窗口中。

本文:Android怎么开发Input系统触摸事件分发的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:Numpy随机抽样如何实现下一篇:

9 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18