SurfaceFlinge/InputFlinger分析-android画面缩放后依然点击正常原理分析

news2024/12/29 9:57:41

hi,粉丝朋友们:
这两天刚好在做自由窗口相关国内需求,刚好遇到一个疑惑,那就是画面进行缩放后发现依然触摸画面可以正常反映问题。
在这里插入图片描述

具体疑惑背景

疑问点如下:
坐标是针对屏幕的,按钮也是相对Activity的,Activity本身宽度和屏幕一样只是画面被缩放了,Activity和View其实依然是屏幕的宽度,那么为啥屏幕坐标点点击到缩放Activity时候,按钮依然可以正常相应呢?

疑惑解答坐标追踪:

回忆坐标传递流程:
触摸事件坐标肯定是 inputdispatcher -----> app

inputdispatcher坐标确定

那么先确定inputDispatcher传递坐标,这个inputdispatcher的坐标其实是可以通过dumpys来查看:

  RecentQueue: length=10
    MotionEvent(deviceId=11, eventTime=37449374871000, source=TOUCHSCREEN | STYLUS, displayId=0, action=MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=22.8, yPrecision=11.1, xCursorPosition=nan, yCursorPosition=nan, pointers=[0: (1011.9, 909.9)]), policyFlags=0x62000000, age=1525ms
    MotionEvent(deviceId=11, eventTime=37449382843000, source=TOUCHSCREEN | STYLUS, displayId=0, action=MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=22.8, yPrecision=11.1, xCursorPosition=nan, yCursorPosition=nan, pointers=[0: (1011.9, 901.0)]), policyFlags=0x62000000, age=1517ms
    MotionEvent(deviceId=11, eventTime=37449390835000, source=TOUCHSCREEN | STYLUS, displayId=0, action=MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=22.8, yPrecision=11.1, xCursorPosition=nan, yCursorPosition=nan, pointers=[0: (1011.9, 898.9)]), policyFlags=0x62000000, age=1509ms
    MotionEvent(deviceId=11, eventTime=37449470965000, source=TOUCHSCREEN | STYLUS, displayId=0, action=MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=22.8, yPrecision=11.1, xCursorPosition=nan, yCursorPosition=nan, pointers=[0: (1011.9, 901.0)]), policyFlags=0x62000000, age=1429ms
    MotionEvent(deviceId=11, eventTime=37449478951000, source=TOUCHSCREEN | STYLUS, displayId=0, action=MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=22.8, yPrecision=11.1, xCursorPosition=nan, yCursorPosition=nan, pointers=[0: (1011.9, 903.0)]), policyFlags=0x62000000, age=1421ms
    MotionEvent(deviceId=11, eventTime=37449486891000, source=TOUCHSCREEN | STYLUS, displayId=0, action=MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=22.8, yPrecision=11.1, xCursorPosition=nan, yCursorPosition=nan, pointers=[0: (1011.9, 907.9)]), policyFlags=0x62000000, age=1413ms
    MotionEvent(deviceId=11, eventTime=37449599726000, source=TOUCHSCREEN | STYLUS, displayId=0, action=MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=22.8, yPrecision=11.1, xCursorPosition=nan, yCursorPosition=nan, pointers=[0: (1011.9, 904.9)]), policyFlags=0x62000000, age=1300ms
    MotionEvent(deviceId=11, eventTime=37449607604000, source=TOUCHSCREEN | STYLUS, displayId=0, action=MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=22.8, yPrecision=11.1, xCursorPosition=nan, yCursorPosition=nan, pointers=[0: (1011.9, 901.0)]), policyFlags=0x62000000, age=1292ms
    MotionEvent(deviceId=11, eventTime=37449615411000, source=TOUCHSCREEN | STYLUS, displayId=0, action=MOVE, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=22.8, yPrecision=11.1, xCursorPosition=nan, yCursorPosition=nan, pointers=[0: (1011.9, 896.9)]), policyFlags=0x62000000, age=1284ms
    MotionEvent(deviceId=11, eventTime=37449783797000, source=TOUCHSCREEN | STYLUS, displayId=0, action=UP, actionButton=0x00000000, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, classification=NONE, edgeFlags=0x00000000, xPrecision=22.8, yPrecision=11.1, xCursorPosition=nan, yCursorPosition=nan, pointers=[0: (1011.9, 896.9)]), policyFlags=0x62000000, age=1116ms

明显发现坐标pointers=[0: (1011.9, 901.0)]), 这个属于屏幕的绝对坐标,这个时候在inputdispatcher的传递时候并没有被变化成和Activity的View一致坐标,即这里基本可以断定inputdispatcher传递到app依然是屏幕的绝对坐标。

app端坐标确定

app端的坐标,这里一般可以通过debug调试方式,或之打印log的方式:
在这里插入图片描述

这里在最初的的dispatchInputEvent进行了断点,发现坐标已经变成了 1341,1633了

   private void dispatchInputEvent(int seq, InputEvent event) {
        mSeqMap.put(event.getSequenceNumber(), seq);
        onInputEvent(event);
    }

即坐标一旦到了java层面其实就已经变成了和Activity正常的坐标了,那么只能继续往app层面地方往下追,这里就需要对native层面的input流程比较了解了,这里可以看马哥的input专题有讲解
在这里插入图片描述
那就来重点看看NativeInputEventReceiver::consumeEvents和InputConsumer.consume方法读取相关input数据情况,最终发现MotionEvent是在void InputConsumer::initializeMotionEvent进行构造出来的:

void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) {
    uint32_t pointerCount = msg->body.motion.pointerCount;
    PointerProperties pointerProperties[pointerCount];
    PointerCoords pointerCoords[pointerCount];
    for (uint32_t i = 0; i < pointerCount; i++) {
        pointerProperties[i].copyFrom(msg->body.motion.pointers[i].properties);
        pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
        ALOGE("initializeMotionEvent: pointerCount x= %f y = %f" ,pointerCoords[i].getX(),pointerCoords[i].getY());
    }
		//这里是坐标变化的关键转换矩阵
    ui::Transform transform;
    transform.set({msg->body.motion.dsdx, msg->body.motion.dtdx, msg->body.motion.tx,
                   msg->body.motion.dtdy, msg->body.motion.dsdy, msg->body.motion.ty, 0, 0, 1});
    ui::Transform displayTransform;
    displayTransform.set({msg->body.motion.dsdxRaw, msg->body.motion.dtdxRaw,
                          msg->body.motion.txRaw, msg->body.motion.dtdyRaw,
                          msg->body.motion.dsdyRaw, msg->body.motion.tyRaw, 0, 0, 1});
    event->initialize(msg->body.motion.eventId, msg->body.motion.deviceId, msg->body.motion.source,
                      msg->body.motion.displayId, msg->body.motion.hmac, msg->body.motion.action,
                      msg->body.motion.actionButton, msg->body.motion.flags,
                      msg->body.motion.edgeFlags, msg->body.motion.metaState,
                      msg->body.motion.buttonState, msg->body.motion.classification, transform,
                      msg->body.motion.xPrecision, msg->body.motion.yPrecision,
                      msg->body.motion.xCursorPosition, msg->body.motion.yCursorPosition,
                      displayTransform, msg->body.motion.downTime, msg->body.motion.eventTime,
                      pointerCount, pointerProperties, pointerCoords);
    ALOGE("initializeMotionEvent:2  pointerCount x= %f y = %f" ,event->getX(0),event->getY(0));
}

这里加入了相关的打印如下:

06-15 23:40:24.413  1850  1850 E InputTransport: initializeMotionEvent: pointerCount x= 1045.942383 y = 930.961914
06-15 23:40:24.413  1850  1850 E InputTransport: initializeMotionEvent:2  pointerCount x= 1371.884766 y = 1693.923828

即可以看出,其实第一步从socket接受到的event坐标依然是和inputdispatcher一样,但是经过event->initialize方法后,再打印时候就发现已经变化了,变成和实际Activity一样的相匹配的坐标了。
其实本质原因还是因为initialize时候有传递相关的transform影响的,因为getX方法时候实际会调用到对应方法进行坐标转换返回:

 /**
     * Get the X coordinate of the latest sample in this MotionEvent for pointer 'pointerIndex'.
     * Identical to calling getHistoricalX(pointerIndex, getHistorySize()).
     */
    inline float getX(size_t pointerIndex) const {
        return getAxisValue(AMOTION_EVENT_AXIS_X, pointerIndex);
    }
    float MotionEvent::getAxisValue(int32_t axis, size_t pointerIndex) const {
    return getHistoricalAxisValue(axis, pointerIndex, getHistorySize());
}

float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex,
                                          size_t historicalIndex) const {
    const PointerCoords& coords = *getHistoricalRawPointerCoords(pointerIndex, historicalIndex);
    //注意这个时候就是会有对应的mTransform进行影响,导致坐标和屏幕坐标产生差异
    return calculateTransformedAxisValue(axis, mSource, mTransform, coords);
}

上面清楚了,那剩下问题就是这个mTransform根源是来自哪里呢?
这里就又要回到inputdispatcher是有传递类似这种mTransform的。

   // Publish the motion event.
                status = connection->inputPublisher
                                 .publishMotionEvent(dispatchEntry->seq,
                                                     dispatchEntry->resolvedEventId,
                                                     motionEntry.deviceId, motionEntry.source,
                                                     motionEntry.displayId, std::move(hmac),
                                                     dispatchEntry->resolvedAction,
                                                     motionEntry.actionButton,
                                                     dispatchEntry->resolvedFlags,
                                                     motionEntry.edgeFlags, motionEntry.metaState,
                                                     motionEntry.buttonState,
                                                     motionEntry.classification,
                                                     dispatchEntry->transform,//这里就是关键的transform也会传递
                                                     motionEntry.xPrecision, motionEntry.yPrecision,
                                                     motionEntry.xCursorPosition,
                                                     motionEntry.yCursorPosition,
                                                     dispatchEntry->rawTransform,
                                                     motionEntry.downTime, motionEntry.eventTime,
                                                     motionEntry.pointerCount,
                                                     motionEntry.pointerProperties, usingCoords);

这个transform其实dumpsys的input中也有展示:

      5: name='692067c com.example.myapplication11/com.example.myapplication11.MainActivity', id=163, displayId=0, inputConfig=0x0, alpha=1.00, frame=[360,84][1080,972], globalScale=1.000000, applicationInfo.name=ActivityRecord{f9088f2 u0 com.example.myapplication11/.MainActivity} t465}, applicationInfo.token=0x7079fae2c370, touchableRegion=[308,32][1133,1025], ownerPid=1850, ownerUid=10116, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTED
        transform (ROT_0) (SCALE TRANSLATE)
            2.0000  -0.0000  -720.0000
            -0.0000  2.0000  -168.0000
            0.0000  0.0000  1.0000

可以看到这个transform,大致矩阵即可以看出有放大2倍和偏移-720.0000,-168.0000,也正是这个转换才导致的由屏幕的绝对坐标转换到Activity的绝对坐标,转换后Activity可以获取到正常的坐标进行响应。

那么问题又来了请问inputdispatcher这个transform的转换又来自哪里呢?

哈哈这里就又回到之前input的专题讲解的,这个windowinfo信息实际是来自于SurfaceFlinger的,这里来看看dumpsys SurfaceFlinger是否又相关信息:

* Layer 0x71a7e2b523f0 (com.example.myapplication11/com.example.myapplication11.MainActivity#268)
      isSecure=false geomUsesSourceCrop=true geomBufferUsesDisplayInverseTransform=false geomLayerTransform (ROT_0) (SCALE TRANSLATE)
    0.5000  0.0000  360.0000
    0.0000  0.5000  84.0000
    0.0000  0.0000  1.0000

找到对应的window Layer确实看到了一个矩阵,但是好像这个矩阵和input的矩阵不一样,但是好像有点关系,这个关系是啥呢?哈哈就是一个类是逆向过程,相当于surface显示时候缩小到原来0.5,那么回去时候就需要放大2倍才可以还原。而surfaceflinger这个矩阵就是进行surfacecontrol进行操作的缩放矩阵。

故到此整个环节就已经清楚了,总结一下如下图:

在这里插入图片描述

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

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

相关文章

【SPI】STM32 SPI 双机通信,SPI从机模式使用

文章目录 一、SPI主机配置二、SPI从机配置三、双机通信1 轮询中断&#xff08;低速&#xff09;2 轮询DMA&#xff08;低速&#xff09;3 DMADMA&#xff08;高速&#xff09;4 开启CRC校验&#xff08;自选&#xff09; 四、遇到的问题1 高速使用时&#xff0c;程序卡死&#…

JavaScript 原型与原型链

所有的 JavaScript 对象都会从一个 prototype&#xff08;原型对象&#xff09;中继承属性和方法&#xff1a; Date 对象从 Date.prototype 继承。 Array 对象从 Array.prototype 继承。 所有 JavaScript 中的对象都是位于原型链顶端的 Object 的实例。 JavaScript 对象有一个指…

【C#】代码解析--打印数据集

系列文章 【C#】编号生成器&#xff08;定义单号规则、固定字符、流水号、业务单号&#xff09; 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/129129787 【C#】日期范围生成器&#xff08;开始日期、结束日期&#xff09; 本文链接&#xff1a;h…

LangChain:LLM应用程序开发(中)——文档问答、评估、Agents(代理)

文章目录 四、文档问答4.1 快速入门4.2 逐步实现4.3 其它方法 五、评估5.1 创建QA app5.2 生成测试数据点5.2.1 Hard-coded examples5.2.2 LLM-Generated examples 5.3 link chain debug手动评估5.4 LLM assisted evaluation5.5 LangChain Evaluation platform 六、Agents&…

704.二分查找

一、题目 二、代码 #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> int search(int* nums, int numsSize, int target) {int left 0;int right numsSize - 1;while (left < right) {int middle (left right) / 2;if (target > nums[middle]) {left m…

pip3 报错 distribution was not found and is required by the application

环境&#xff1a; centos 8 &#xff0c; pyhton3.6 背景&#xff1a; 升级python3.6 至 python3.10后&#xff0c; pip3安装包报错&#xff1a; pkg_resources.VersionConflict: (pip 21.2.4 (/usr/local/python3/lib/python3.10/site-packages), Requirement.parse(pip23.…

Linux:scp命令

1.介绍 scp命令是cp命令的升级版&#xff0c;即&#xff1a;ssh cp&#xff0c;通过SSH协议完成文件的复制。其主要的功能就是&#xff1a;在不同的Linux服务器之间&#xff0c;通过SSH协议互相传输文件。只要知晓服务器的账户和密码&#xff08;或密钥&#xff09;&#xff0c…

美光之后,韩国存储芯片也将成为输家,将损失千亿美元

美光很可能将完全丧失中国的企业市场&#xff0c;随着影响的扩大&#xff0c;韩国存储芯片或也将因美光的影响而蒙受巨大的损失&#xff0c;预计损失最高可能达到千亿美元&#xff0c;韩国存储芯片的老大地位也将因此动摇。 美光日前对媒体披露的数据指出因中国的安全审查&…

GitHub下的项目有pom.xml但右侧没有Maven问题

1.可以使用idea自带功能将pom.xml作为Maven导入 双击shift&#xff0c;输入Maven点击Add Maven Projects注意&#xff1a;在settings中将Maven先配置好&#xff0c;我使用的是自己设置的Maven仓库而不是idea自动部署在C盘的仓库

SQL Server数据库 -- 表的创建与管理

文章目录 一、数据表的组成二、创建数据表 表的创建表的查看表的增加表的修改表的删除、三、表的架构操作四、总结 前言 上次博客写到了数据库的创建与管理&#xff0c;但是创建的库里面什么东西都没有&#xff0c;现在我们需要在库里面添加数据表内容 一、数据表的组成 在创…

美好未来“一束光”儿童安全教育项目在四川泸定正式启动

6月26日&#xff0c;由中华少年儿童慈善救助基金会和北京臻爱公益基金会共同发起的美好未来计划“一束光”儿童安全教育公益项目启动仪式&#xff0c;在四川省甘孜藏族自治州泸定县贡嘎山片区寄宿制学校举行。 出席本次启动仪式活动的嘉宾有&#xff1a;中华少年儿童慈善救助基…

基于“SRP模型+”多技术融合在生态环境脆弱性评价模型构建、时空格局演变分析与RSEI指数的生态质量评价及拓展应用

目录 ​第一章 生态环境脆弱性评价内涵及基于文献可视化方法研究热点分析 第二章 数据来源及预处理 第三章 生态环境脆弱性评价模型构建 第四章 生态环境脆弱性时空格局演变分析 第五章 生态环境脆弱性时空格局演变驱动机制分析 第六章 基于 RSEI 指数的生态质量评价 第…

js输入一个字符串,打印出该字符串中,所有字符的排列组合(超清晰)

一、题目 输入一个字符串&#xff0c;打印出该字符串中&#xff0c;所有字符的排列组合。 输入&#xff1a;abc 输出&#xff1a;[abc, acb, bca, bac, cab, cba] 二、思路 回溯算法。其核心思想是通过递归的方式进行深度优先搜索&#xff0c;当发现当前的选择不符合要求时…

机器学习技术:如何使用交叉验证和ROC曲线提高疾病预测的准确性和效率?

一、引言 随着机器学习的普及&#xff0c;评估模型的性能越来越重要。交叉验证和ROC曲线是两种常见的评估模型性能的方法。本文将介绍这两种方法的基本原理和应用场景&#xff0c;并结合实际案例和技术实践&#xff0c;讲解如何使用交叉验证和ROC曲线来提高机器学习模型的性能…

mongodb原理

一&#xff1a;MongoDB的优点和缺点 优点 面向文档存储(类JSON数据模式简单而强大)动态查询全索引支持,扩展到内部对象和内嵌数组查询记录分析快速,就地更新高效存储二进制大对象 (比如照片和视频)复制和故障切换支持Auto- Sharding自动分片支持云级扩展性MapReduce 支持复杂…

chatgpt赋能python:Python选择对话框:简化用户操作的实用工具

Python选择对话框&#xff1a;简化用户操作的实用工具 在Python编程领域中&#xff0c;常常需要与用户进行交互&#xff0c;以便更好地控制程序运行结果。而选择对话框则是一种简化用户操作的实用工具&#xff0c;可避免用户输入错误或步骤繁琐的问题。在本篇文章中&#xff0…

【UE】一个需求案例掌握Timeline和插值Lerp

文章目录 问题背景结论先行timeline和lerp原理使用timelinelerp实现相机平滑跟随BUG猜想验证和解决 问题背景 今天用timelinelerp插值做了一个相机平滑跟随的需求 如果只是要求跟随&#xff0c;直接在tick中把相机位置设置成角色位置就可以 但希望有一个相机滞后角色一点点的…

如何避免ChatGPT,ChatGLM这类大语言模型胡说八道

“ ChatGPT&#xff0c;ChatGLM这类大语言模型一本正经的胡说八道&#xff0c;可能也是它创造性回答的部分。那么谁来判断它在编造无中生有的内容&#xff1f;恐怕只有人才能判断。模型怎么会产生幻觉&#xff0c;我们又怎么避免它产生幻觉&#xff1f;” 01 — 昨天体验了国产…

快上车,搭乘HUAWEI HiCar驶向未来

HUAWEI HiCar&#xff08;以下简称HiCar&#xff09;是华为提供的人-车-家全场景智慧互联解决方案&#xff0c;连接手机与车辆&#xff0c;充分发挥各自的优势属性&#xff0c;将手机的应用/服务生态延伸进车辆&#xff0c;实现以手机为核心的全场景体验。消费者通过HiCar可以感…

HTML 超链接标签、图片标签

超链接标签 超链接描述 HTML使用标签<a>来设置超文本链接 超链接可以是一个字&#xff0c;一个词&#xff0c;或者一组词&#xff0c;也可以是一幅图像&#xff0c;您可以点击这些内容来跳转到新的文档或者当前文档中的某个部分。 <a href"url">链接文…