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

这篇具有很好参考价值的文章主要介绍了SurfaceFlinge/InputFlinger分析-android画面缩放后依然点击正常原理分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

hi,粉丝朋友们:
这两天刚好在做自由窗口相关国内需求,刚好遇到一个疑惑,那就是画面进行缩放后发现依然触摸画面可以正常反映问题。
SurfaceFlinge/InputFlinger分析-android画面缩放后依然点击正常原理分析

具体疑惑背景

疑问点如下:
坐标是针对屏幕的,按钮也是相对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的方式:
SurfaceFlinge/InputFlinger分析-android画面缩放后依然点击正常原理分析

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

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

即坐标一旦到了java层面其实就已经变成了和Activity正常的坐标了,那么只能继续往app层面地方往下追,这里就需要对native层面的input流程比较了解了,这里可以看马哥的input专题有讲解
SurfaceFlinge/InputFlinger分析-android画面缩放后依然点击正常原理分析
那就来重点看看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进行操作的缩放矩阵。

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

SurfaceFlinge/InputFlinger分析-android画面缩放后依然点击正常原理分析文章来源地址https://www.toymoban.com/news/detail-507621.html

到了这里,关于SurfaceFlinge/InputFlinger分析-android画面缩放后依然点击正常原理分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android 画面显示流程二

    BufferQueue BufferQueue要解决的是生产者的同步问题,应用程序生产画面,SurfaceFlinger消费画面,SurfaceFlinger生产画面而HWCService消费画面。用来存储这些画面的存储区我们称其为帧缓冲区buffer,下面我们以应用程序作为生产者,SurfaceFlinger作为消费者为例来了解一下BufferQueue的内部设

    2024年02月13日
    浏览(57)
  • Android Camera预览画面变形问题

    csdn 安卓camera1在预览时,预览画面看起来被拉伸了. 如图,圆形的盖子,变成椭圆形了. 默认流程,如下为大致的打开摄像头并进行预览显示的代码 网上大部分的解决方法(实测不一定有效) 原理是遍历摄像头分辨率,找到与当前屏幕契合的分辨率,并设置为预览大小. 如下

    2024年02月13日
    浏览(74)
  • Android OpenGL 渲染相机预览画面显示体系

    OpenGL能进行高效得渲染图形图像,并支持各种复杂的特效和动画。 而在 Android 当中,运用的是 OpenGL ES ,它是OpenGL的一个 轻量级版本 ,专门用于在移动设备、游戏控制台、嵌入式系统等嵌入式环境中使用。 它可以做相机滤镜或者图片滤镜的效果,以相机滤镜为例: 首先 C

    2023年04月24日
    浏览(45)
  • Android实时获取摄像头画面传输至PC端

    最近在做一个PC端小应用,需要获取摄像头画面,但是电脑摄像头像素太低,而且位置调整不方便,又不想为此单独买个摄像头。于是想起了之前淘汰掉的手机,成像质量还是杠杠的,能不能把手机摄像头连接到电脑上使用呢?经过搜索,在网上找到了几款这类应用,但是都

    2024年02月12日
    浏览(51)
  • Android USBCamera投屏 - 利用UVC协议将手机上的画面有线投屏到Android车机的屏幕上

    1. 背景 一个需求 : 要将手机上的画面和音频 投屏 到 车机的Android屏幕上。 车机有一个支持OTG的USB-A口,由于设备有限,我们有一个USB-A转HDMI转接口,一跟HDMI线,一个USB-C的拓展坞 (包括HDMI口,两个USB-A口,一个网口),我们将这几根线接在一起,成功将手机和车机连在了一起

    2024年02月08日
    浏览(45)
  • Android 点击图片,放大查看,实现缩放拖动等功能

    实现方法:点击图片时,把图片url传到另一个activity中实现放大拖动, 图片点击事件触发: Intent intent = new Intent(); intent.setClass(mContext, PictureActivity.class); intent.putExtra(“url”,R.drawable.ic_logo); mContext.startActivity(intent); 然后创建一个activity的内容如下: public class PictureActivity extend

    2024年02月11日
    浏览(54)
  • Android 实现单指滑动、双指缩放照片

    最近接到一个查看大图的需求,现在图片展示还不够大,要求还要能缩小能放大还能保存照片。直接开始Google实现方式。 根据查询到的结果分为两种,一个是使用手势监听来实现,第二种监听触摸事件来实现 手势监听-- ScaleGestureDetector Google提供的手势监听类 触摸事件–OnT

    2024年02月11日
    浏览(41)
  • 【Android】Bitmap图片旋转、缩放、翻转等变换(90/100)

    自定义BitmapChangeView: 工具类: 布局引用: 应用如下: 推荐理由 postman在国内使用已经越来越困难: 1、登录问题严重 2、Mock功能服务基本没法使用 3、版本更新功能已很匮乏 4、某些外力因素导致postman以后能否使用风险较大 出于以上考虑因此笔者自己开发了一款api调试开发工

    2024年02月16日
    浏览(36)
  • Android控件双指缩放及双指拖动

    本文章分为两部分,第一部分先讲解下需要用到的知识点,第二部分提供代码实例。 以上就是全部内容了,谢谢观看。

    2024年02月14日
    浏览(44)
  • Android Studio新功能-设备镜像Device mirroring-在电脑侧显示手机实时画面并可控制

    下载最新的灰测版本-蜥蜴 成功运行到真机后,点击右侧Running Devices选项卡,再点击+号 选中当前设备; 非常丝滑同步,在电脑侧也可以顺畅控制真机 该功能大大方便了我们视线保持在显示器上专注开发,并且便于与UI视觉进行校准与比对。 Device mirroring You can now mirror your p

    2024年02月08日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包