【Android】WMS(五)输入事件原理

news2024/11/27 6:18:25

输入事件原理

安卓输入事件整体流程

Android 系统是由事件驱动的,而 input 是最常见的事件之一,用户的点击、滑动、长按等操作,都属于 input 事件驱动,其中的核心就是 InputReader 和 InputDispatcher。

InputReader 和 InputDispatcher 是跑在 SystemServer进程中的两个 native 循环线程,负责读取和分发 Input 事件。整个处理过程大致流程如下:

在这里插入图片描述

InputManagerService

在SystemServer的startOtherServices函数中,会新建一个InputManagerService对象,然后会作为参数传入到WMS中去。

inputManager = new InputManagerService(context);
......
wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
                    new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);

WindowInputEventReceiver输入事件监听

在ViewRootImpl的setView函数中,会先建立一个InputChannel对象。inputChannel是输入事件的信道,它ViewRootImpl和InputManagerService的沟通桥梁。

 InputChannel inputChannel = null;
 if ((mWindowAttributes.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
      inputChannel = new InputChannel();
 }

inputChannel会通过mWindowSession.addToDisplayAsUser方法传入到WMS侧,并且与当前新建窗口WindowState建立起关系

if  (openInputChannels) {
	//WindowState与InputChannel关联上了
    win.openInputChannel(outInputChannel);
}

之后代码运行到ViewRootImpl侧,这个时候就开始生成监听对象

if (inputChannel != null) {
                    if (mInputQueueCallback != null) {
                        mInputQueue = new InputQueue();
                        mInputQueueCallback.onInputQueueCreated(mInputQueue);
                    }
   					// 输入事件的监听对象
                    mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
                            Looper.myLooper());
                }

}

EventHub设备事件监听

它主要是利用Linux的inotify和epoll机制,监听设备事件:包括设备插拔及各种触摸、按钮事件等,可以看做是一个不同设备的集线器,主要面向的是/dev/input目录下的设备节点,比如说/dev/input/event0上的事件就是输入事件:

在这里插入图片描述

InputReader读取事件

InputReader主要是负责不断的从EventHub读取事件,通知派发给InputDispatcher。

void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    std::vector<InputDeviceInfo> inputDevices;
    { 
    ......
    // 读取EventHub中的事件
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
   ......
   // 通知派发给InputDispatcher
   mQueuedListener->flush();
}

InputDispatcher读取事件

void InputDispatcher::dispatchOnce() {
    nsecs_t nextWakeupTime = LONG_LONG_MAX;
    { // acquire lock
        ......
        // 被唤醒 ,处理Input消息
        if (runCommandsLockedInterruptible()) {
            nextWakeupTime = LONG_LONG_MIN;
        }
    
       .....
    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
    //睡眠等到事件
    mLooper->pollOnce(timeoutMillis);
}

寻找目标窗口

Android系统能够同时支持多块屏幕,每块屏幕被抽象成一个DisplayContent对象,内部维护一个WindowList列表对象,用来记录当前屏幕中的所有窗口,包括状态栏、导航栏、应用窗口、子窗口等。对于触摸事件,我们比较关心可见窗口

那么,如何找到触摸事件对应的窗口呢,是状态栏、导航栏还是应用窗口呢,这个时候DisplayContent的WindowList就发挥作用了,DisplayContent握着所有窗口的信息,因此,可以根据触摸事件的位置及窗口的属性来确定将事件发送到哪个窗口,当然其中的细节比一句话复杂的多,跟窗口的状态、透明、分屏等信息都有关系,下面简单瞅一眼,达到主观理解的流程就可以了,然后会调用到InputDispatcher#findTouchedWindowAtLocked

// 遍历所有窗口 
for (const sp<InputWindowHandle>& windowHandle : windowHandles) {
        const InputWindowInfo* windowInfo = windowHandle->getInfo();
        if (windowInfo->displayId == displayId) {
            int32_t flags = windowInfo->layoutParamsFlags;

            if (windowInfo->visible) {
                if (!(flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {
                    bool isTouchModal = (flags &
                                         (InputWindowInfo::FLAG_NOT_FOCUSABLE |
                                          InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
                    if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
                        int32_t portalToDisplayId = windowInfo->portalToDisplayId;
                        ......
                        // Found window. 找到目标窗口
                        return windowHandle;
                    }
                }
            }
        }

mWindowHandles代表着所有窗口,找到了目标窗口,同时也将事件封装好了,剩下的就是通知目标窗口,可是有个最明显的问题就是,目前所有的逻辑都是在SystemServer进程,而要通知的窗口位于APP端的用户进程,那么如何通知呢?这里面采用的都是Socket的通信方式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/627162.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

申请国家标准项目管理专业人员能力评级(CSPM)报名条件有哪些?

2021年10月&#xff0c;中共中央、国务院发布的《国家标准化发展纲要》明确提出构建多层次从业人员培养培训体系&#xff0c;开展专业人才培养培训和国家质量基础设施综合教育。建立健全人才的职业能力评价和激励机制。由中国标准化协会&#xff08;CAS&#xff09;组织开展的项…

3.JavaScript常用对象数组对象

3.1、数组对象 3.1.1、概述 目录 3.1、数组对象 3.1.1、概述 3.1.2、创建数组 3.1.2.1、使用对象创建 3.1.2.2、使用字面量创建 3.1.3、遍历数组 3.1.4、数组属性 3.1.5、数组方法 3.2、函数对象 3.2.1、call()和apply() 3.2.2、this指向 3.2.3、arguments参数 3…

JavaSE-06 [面向对象+封装]

JavaSE-06 [面向对象封装] 第一章 面向对象思想 1.1 面向过程和面向对象 面向过程&#xff1a; 面向过程就是分析出解决问题所需要的步骤&#xff0c;然后用函数把这些步骤一步一步实现&#xff0c;使用的时候一个一个依次调用就可以了面向对象&#xff1a; 面向对象是把构成…

PYTHON元素定位方式总结

一&#xff0c;常用的8种定位方式 id定位 driver.find_element_by_id("id 值")   driver.find_element(by "id", value "ID值" ) name定位 单个元素&#xff1a;     driver.find_element_by_name("name值")     drive…

总结:记一次docker调试镜像的问题

一、背景 同事让帮忙部署一个应用到QKE&#xff0c;给了我镜像地址与配置文件。 由于要将配置文件映射到容器中&#xff0c;我创建了configmap&#xff0c;然后应用中将configmap中key对应的内容映射到了容器中的配置文件中。 但是我遇到了一个问题&#xff1a; 容器频繁快…

100多的ipad触控笔好用吗?ipad可以用的手写笔推荐

随着IPAD的普及&#xff0c;一些学习党已经从传统的纸质教学走向了无纸化教学。所以&#xff0c;本来就是苹果品牌专利的电容笔&#xff0c;现在更是成为了炙手可热的产品&#xff0c;很多人都对这款售价近千元的电容笔充满了好奇。我认为&#xff0c;对于职业画师来说&#xf…

你“心累”吗?教你方法

解决“心累”的方法来了 前言一、“心累”的原因二、认识“心累”三、走出“心累”四、发现自己的“优势” 前言 不管是脑力劳动还是体力劳动&#xff0c;工作生活本身并没有多么累&#xff0c;但总感觉累。这就是我今天想说的话题&#xff1a;心累。 如果你也被这个状态折磨&a…

用好 mysql 分区表

为了保证mysql的性能&#xff0c;我们都建议mysql单表不要太大&#xff0c;也经常有人问我这样的问题&#xff0c;整体来说呢&#xff0c;建议是&#xff1a;单表小于2G&#xff0c;记录数小于1千万&#xff0c;十库百表。如果但行记录数非常小&#xff0c;那么记录数可以再偏大…

粮油企业MES系统源码 粮油质量管控防伪溯源系统

粮油企业MES系统源码 粮油企业质量管控防伪溯源系统源码 粮油企业ERP系统源码 农产品MES系统源码 农产品溯源系统源码 利用物联网、云计算 、区块链、人工智能、5G等先进技术&#xff0c;结合特有的码码关联和RSA加密验证技术&#xff0c;开发的一套粮油质量管控防伪溯源系统&…

C++ 设计模式 包装类型(Wrapper Type)的运用:运算符重载的包装类型策略

目录标题 1. 运算符重载与包装类型&#xff08;Wrapper Type&#xff09;1.1 运算符重载的基本概念1.2 包装类型的定义与应用1.3 运算符重载与包装类型的结合 2. 包装类型的设计与实现2.1 包装类型的基本设计2.2 运算符重载的实现2.3 包装类型与原始类型的转换 3. 包装类型的性…

基于jsp+mysql+Spring+mybatis+Springboot的SpringBoot停车场停车位管理系统

运行环境: 最好是java jdk 1.8&#xff0c;我在这个平台上运行的。其他版本理论上也可以。 IDE环境&#xff1a; Eclipse,Myeclipse,IDEA或者Spring Tool Suite都可以&#xff0c;如果编译器的版本太低&#xff0c;需要升级下编译器&#xff0c;不要弄太低的版本 tomcat服务器环…

阿里巴巴内部10w字Java面试小抄火了,完整版开放下载

Java 面试 “金九银十”这个字眼对于程序员应该是再熟悉不过的了&#xff0c;每年的金九银十都会有很多程序员找工作、跳槽等一系列的安排。说实话&#xff0c;面试中 7 分靠能力&#xff0c;3 分靠技能&#xff1b;在刚开始的时候介绍项目都是技能中的重中之重&#xff0c;它…

【3步教程】如何使用商城小程序源码打造自己的商城?

作为电商行业的领头人&#xff0c;在移动端上拥有一款独立小程序绝对是不能缺少的&#xff0c;而使用商城小程序源码打造自己的商城则是最佳的选择之一。本文将教您如何在3步之内&#xff0c;快速高效地使用商城小程序源码&#xff0c;打造属于自己的小程序商城。 步骤一&…

深度解析Java程序员从入行到被裁全过程

很多年以前&#xff0c;我拿着 2000 的月薪入职了一家电商创业公司&#xff0c;整个公司只有一个会画饼的老板和啥也不会的我。 一切都是从零开始。 入职第一天&#xff0c;老板说我们首先需要一个网页。 于是我现学现卖了 HTML、CSS、JavaScript&#xff0c;做出来的界面大…

从古至今数据安全的守护者:哈希算法和加密方法的数据安全进化之旅

1、哈希算法进化史 在当今的数字化世界中&#xff0c;数据的安全性和完整性是至关重要的。哈希算法作为一种核心的密码学工具&#xff0c;用于生成数据的唯一标识和验证数据的完整性。然而&#xff0c;随着技术的进步和安全威胁的不断演化&#xff0c;早期的哈希算法逐渐暴露出…

【计算机组成与体系结构Ⅰ】章节测试(4)

指令系统采用不同寻址方式的目的是( ) A&#xff0e;实现存贮程序和程序控制 B&#xff0e;缩短指令长度&#xff0c;扩大寻址空间&#xff0c;提高编程灵活性 C&#xff0e;可直接访问外存 D&#xff0e;提供扩展操作码的可能并降低指令译码的难度 下列寻址方式中&#xf…

【C51】10-基础51单片机的小车项目(51完结)

10.1小车的安装 10.2电机模块的开发&#xff08;L9110S&#xff09; 接通 VCC &#xff0c; GND 模块电源指示灯亮&#xff0c; 以下资料来源官方&#xff0c;但是不对&#xff0c;根据下节课实际调试 IA1 输入高电平&#xff0c; IA1 输入低电平&#xff0c;【 OA1 OB1 】电…

IIC电平转换电路原理分析

一&#xff0c;简介 本文主要介绍IIC电平转换电路的原理&#xff0c;记录总结。 二&#xff0c;准备知识&#xff08;芯片介绍AW39114BQNR&#xff09; 登录官网&#xff0c;搜索该芯片的名称&#xff0c;查看对应的芯片手册。 芯片介绍&#xff1a; 典型应用电路&#xf…

【RISCV】RISCV e-906实现Tickless

Tickless 最初设计的思想是,能被任务唤醒,也能被中断唤醒 参考文章: freeRTOS 低功耗模式 和 空闲任务 FreeRTOS源码分析与应用开发09:低功耗Tickless模式 FreeRTOS学习十(低功耗) 【STM32】NVIC与中断控制 之 sysTick定时器 M3,M4实现tickleess的做法: M3,M4的机制:…

AIGC时代,基于云原生 MLOps 构建属于你的大模型(上)

为了满足企业在数字化转型过程中对更新迭代生产力工具的需求&#xff0c;灵雀云近日推出了云原生 MLOps 解决方案&#xff0c;帮助企业快速落地AI技术、实现智能化应用和服务。 为什么要打造云原生MLOps解决方案&#xff1f; 随着信息化技术的不断发展&#xff0c;企业在数字化…