Android 11 触摸小圆点显示流程

在开发者选项中,打开 “显示点按操作反馈” 开关,当我们在触摸屏幕时,会显示一个小圆点,来分析下小圆点的显示流程。
操作这个开关时,其实就是操作Settings数据库中的 SHOW_TOUCHES

//packages\apps\Settings\src\com\android\settings\development\ShowTapsPreferenceController.java
@Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        final boolean isEnabled = (Boolean) newValue;
        Settings.System.putInt(mContext.getContentResolver(),
                Settings.System.SHOW_TOUCHES, isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
        return true;
    }

而在IMS中,会对 SHOW_TOUCHES 这个key进行监听

//frameworks\base\services\core\java\com\android\server\input\InputManagerService.java
private void registerShowTouchesSettingObserver() {
        mContext.getContentResolver().registerContentObserver(
                Settings.System.getUriFor(Settings.System.SHOW_TOUCHES), true,
                new ContentObserver(mHandler) {
                    @Override
                    public void onChange(boolean selfChange) {
                        updateShowTouchesFromSettings();
                    }
                }, UserHandle.USER_ALL);
    }

当SHOW_TOUCHES 这个key的值有改变时,调用updateShowTouchesFromSettings方法,在updateShowTouchesFromSettings方法中,是调用nativeSetShowTouches这个native方法,直接来看下这个方法

//frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp
static void nativeSetShowTouches(JNIEnv* /* env */,
        jclass /* clazz */, jlong ptr, jboolean enabled) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

    im->setShowTouches(enabled);//调用NativeInputManager的setShowTouches方法
}

void NativeInputManager::setShowTouches(bool enabled) {
    { // acquire lock
        AutoMutex _l(mLock);

        if (mLocked.showTouches == enabled) {
            return;
        }

        ALOGI("Setting show touches feature to %s.", enabled ? "enabled" : "disabled");
        mLocked.showTouches = enabled;//1
    } // release lock

    mInputManager->getReader()->requestRefreshConfiguration(
            InputReaderConfiguration::CHANGE_SHOW_TOUCHES);//2
}

注释1处mLocked.showTouches就为传进来的enabled(打开为true,关闭为false),注释2处调用InputReader的requestRefreshConfiguration继续处理

//frameworks\native\services\inputflinger\reader\InputReader.cpp
void InputReader::requestRefreshConfiguration(uint32_t changes) {
    AutoMutex _l(mLock);

    if (changes) {
        bool needWake = !mConfigurationChangesToRefresh;
        mConfigurationChangesToRefresh |= changes;//changes为InputReaderConfiguration::CHANGE_SHOW_TOUCHES

        if (needWake) {
            mEventHub->wake();//唤醒InputReader线程
        }
    }
}

InputReader线程被唤醒,loopOnce继续执行

//frameworks\native\services\inputflinger\reader\InputReader.cpp
void InputReader::loopOnce() {
    //省略
    { // acquire lock
        AutoMutex _l(mLock);
        
        uint32_t changes = mConfigurationChangesToRefresh;
        if (changes) {
            mConfigurationChangesToRefresh = 0;
            timeoutMillis = 0;
            refreshConfigurationLocked(changes);//1
        } else if (mNextTimeout != LLONG_MAX) {
           //省略
        }
    } // release lock

	//省略

注释1处,调用refreshConfigurationLocked继续处理

//frameworks\native\services\inputflinger\reader\InputReader.cpp
void InputReader::refreshConfigurationLocked(uint32_t changes) {
    mPolicy->getReaderConfiguration(&mConfig);//1
    mEventHub->setExcludedDevices(mConfig.excludedDeviceNames);

    if (changes) {
       //省略
        if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) {
            mEventHub->requestReopenDevices();
        } else {
            for (auto& devicePair : mDevices) {
                std::shared_ptr<InputDevice>& device = devicePair.second;
                device->configure(now, &mConfig, changes);//2
            }
        }
    }
}

注释1处主要是将前面的mLocked.showTouches又赋值给mConfig的showTouches,注释2处调用InputDevice的configure继续处理。
1,getReaderConfiguration

//frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp
void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outConfig) {
	//省略

	{ // acquire lock
        AutoMutex _l(mLock);
		//省略

        outConfig->showTouches = mLocked.showTouches;//赋值
		
		//省略
    } //  release lock
}

2,InputDevice:configure

//frameworks\native\services\inputflinger\reader\InputDevice.cpp
void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config,
                            uint32_t changes) {
	//省略
	for_each_mapper([this, when, config, changes](InputMapper& mapper) {
            mapper.configure(when, config, changes);
            mSources |= mapper.getSources();
        });
	//省略

}

对于InputReaderConfiguration::CHANGE_SHOW_TOUCHES,又调用对应mapper的configure处理。多指触摸的话mapper为MultiTouchInputMapper,MultiTouchInputMapper没有实现configure方法,在其父类TouchInputMapper中实现

//frameworks\native\services\inputflinger\reader\mapper\TouchInputMapper.cpp
void TouchInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config,
                                 uint32_t changes) {
    //省略
    if (!changes ||
        (changes &
         (InputReaderConfiguration::CHANGE_DISPLAY_INFO |
          InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT |
          InputReaderConfiguration::CHANGE_SHOW_TOUCHES |
          InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) {
        // Configure device sources, surface dimensions, orientation and
        // scaling factors.
        configureSurface(when, &resetNeeded);
    }
	//省略

调用configureSurface继续处理

//frameworks\native\services\inputflinger\reader\mapper\TouchInputMapper.cpp
void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
	//省略
	// Create pointer controller if needed.
    if (mDeviceMode == DEVICE_MODE_POINTER ||
        (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) {
        if (mPointerController == nullptr) {
            mPointerController = getContext()->getPointerController(getDeviceId());
        }
    } else {
        mPointerController.clear();
    }
	//省略
}

getPointerController方法最终调用InputReader的getPointerControllerLocked方法

//frameworks\native\services\inputflinger\reader\InputReader.cpp
sp<PointerControllerInterface> InputReader::getPointerControllerLocked(int32_t deviceId) {
    sp<PointerControllerInterface> controller = mPointerController.promote();
    if (controller == nullptr) {
        controller = mPolicy->obtainPointerController(deviceId);//1
        mPointerController = controller;
        updatePointerDisplayLocked();//2
    }
    return controller;
}

注释1处创建PointerController对象,注释2处调用updatePointerDisplayLocked继续处理
1,obtainPointerController

//frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp
sp<PointerControllerInterface> NativeInputManager::obtainPointerController(int32_t /* deviceId */) {
    ATRACE_CALL();
    AutoMutex _l(mLock);

    sp<PointerController> controller = mLocked.pointerController.promote();
    if (controller == nullptr) {
        ensureSpriteControllerLocked();//创建SpriteController对象

        controller = new PointerController(this, mLooper, mLocked.spriteController);//创建PointerController对象
        mLocked.pointerController = controller;
        updateInactivityTimeoutLocked();
    }

    return controller;
}

2,updatePointerDisplayLocked

//frameworks\native\services\inputflinger\reader\InputReader.cpp
void InputReader::updatePointerDisplayLocked() {
    sp<PointerControllerInterface> controller = mPointerController.promote();//取出前面创建的PointerController对象
    if (controller == nullptr) {
        return;
    }

   //省略

    controller->setDisplayViewport(*viewport);
}

来看一下PointerController的setDisplayViewport方法

frameworks\base\libs\input\PointerController.cpp
void PointerController::setDisplayViewport(const DisplayViewport& viewport) {
	//省略
		loadResourcesLocked();//加载小圆点图片资源
	//省略

	updatePointerLocked();//保存资源信息到SpriteController中,其中包含了小圆点图片的bitmap

}

loadResourcesLocked加载图片信息,主要是通过JNI调用,调用到PointerIcon中的getSystemIcon方法中

//frameworks\base\core\java\android\view\PointerIcon.java
public static PointerIcon getSystemIcon(@NonNull Context context, int type) {
       //省略
        int typeIndex = getSystemIconTypeIndex(type);
        if (typeIndex == 0) {
            typeIndex = getSystemIconTypeIndex(TYPE_DEFAULT);
        }

        int defStyle = sUseLargeIcons ?
                com.android.internal.R.style.LargePointer : com.android.internal.R.style.Pointer;
        TypedArray a = context.obtainStyledAttributes(null,
                com.android.internal.R.styleable.Pointer,
                0, defStyle);
        int resourceId = a.getResourceId(typeIndex, -1);
        a.recycle();
        
        icon = new PointerIcon(type);
        if ((resourceId & 0xff000000) == 0x01000000) {
            icon.mSystemIconResourceId = resourceId;//设置ID
        } else {
            icon.loadResource(context, context.getResources(), resourceId);
        }
        systemIcons.append(type, icon);
        return icon;
    }

private static int getSystemIconTypeIndex(int type) {
        switch (type) {
            case TYPE_ARROW:
                return com.android.internal.R.styleable.Pointer_pointerIconArrow;
            case TYPE_SPOT_HOVER:
                return com.android.internal.R.styleable.Pointer_pointerIconSpotHover;
            case TYPE_SPOT_TOUCH:
                return com.android.internal.R.styleable.Pointer_pointerIconSpotTouch;
	//省略
}

可以看出,加载的资源ID为pointer_spot_touch_icon

//frameworks\base\core\res\res\drawable\pointer_spot_touch_icon.xml
<?xml version="1.0" encoding="utf-8"?>
<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
    android:bitmap="@drawable/pointer_spot_touch"
    android:hotSpotX="16dp"
    android:hotSpotY="16dp" />

小圆点的图片资源已经被加载,并将其保存在相应的变量中了,接下来就需要将其显示出来了。当有触摸数据产生时,InputReader在读取到数据,然后会调用到cookAndDispatch来处理原始数据

//frameworks\native\services\inputflinger\reader\mapper\TouchInputMapper.cpp
void TouchInputMapper::cookAndDispatch(nsecs_t when) {
	//省略
	if (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches &&
            mPointerController != nullptr) {//如果需要显示小圆点
            mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
            mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);

            mPointerController->setButtonState(mCurrentRawState.buttonState);
            mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords,
                                         mCurrentCookedState.cookedPointerData.idToIndex,
                                         mCurrentCookedState.cookedPointerData.touchingIdBits,
                                         mViewport.displayId);
        }
	//省略
}

主要是通过调用setSpots去处理,在setSpots函数中,主要是先创建一个Spot对象,然后调用其updateSprite方法去请求更新小圆点

//frameworks\base\libs\input\PointerController.cpp
void PointerController::Spot::updateSprite(const SpriteIcon* icon, float x, float y,
        int32_t displayId) {
    sprite->setLayer(Sprite::BASE_LAYER_SPOT + id);
    sprite->setAlpha(alpha);
    sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale));
    sprite->setPosition(x, y);
    sprite->setDisplayId(displayId);
    this->x = x;
    this->y = y;

    if (icon != lastIcon) {
        lastIcon = icon;
        if (icon) {
            sprite->setIcon(*icon);
            sprite->setVisible(true);//显示
        } else {
            sprite->setVisible(false);
        }
    }
}

接下来的流程,主要是通过发送发送MSG_UPDATE_SPRITES消息,然后调用doUpdateSprites来更新绘制小圆点

//frameworks\base\libs\input\SpriteController.cpp
void SpriteController::doUpdateSprites() {
	//省略
	if (update.state.surfaceControl != NULL && !update.state.surfaceDrawn
                && update.state.wantSurfaceVisible()) {
            sp<Surface> surface = update.state.surfaceControl->getSurface();
            ANativeWindow_Buffer outBuffer;
            status_t status = surface->lock(&outBuffer, NULL);
            if (status) {
                ALOGE("Error %d locking sprite surface before drawing.", status);
            } else {
                graphics::Paint paint;
                paint.setBlendMode(ABLEND_MODE_SRC);

                graphics::Canvas canvas(outBuffer, (int32_t) surface->getBuffersDataSpace());
                canvas.drawBitmap(update.state.icon.bitmap, 0, 0, &paint);

                const int iconWidth = update.state.icon.bitmap.getInfo().width;
                const int iconHeight = update.state.icon.bitmap.getInfo().height;

                if (outBuffer.width > iconWidth) {
                    paint.setBlendMode(ABLEND_MODE_CLEAR); // clear to transparent
                    canvas.drawRect({iconWidth, 0, outBuffer.width, iconHeight}, paint);
                }
                if (outBuffer.height > iconHeight) {
                    paint.setBlendMode(ABLEND_MODE_CLEAR); // clear to transparent
                    canvas.drawRect({0, iconHeight, outBuffer.width, outBuffer.height}, paint);
                }

                status = surface->unlockAndPost();

		//省略
}

总结
触摸圆点的显示逻辑都是在InputReader线程中完成。以下为显示的流程图
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据大屏vue3+ts+axios+MockJS+dataV+echarts

一、官网/文档 vue3&#xff1a;https://cn.vuejs.org/api/TypeScript&#xff1a;https://www.tslang.cn/docs/handbook/basic-types.htmlaxios&#xff1a;http://www.axios-js.com/zh-cn/docs/MockJS&#xff1a;http://mockjs.com/dataV&#xff1a;http://datav.jiamingh…

马斯克xAI融资60亿美元,宣布打造世界第一超算中心,10万张H100GPU

昨天&#xff0c;埃隆马斯克的xAI初创公司宣布获得60亿美元的巨额融资&#xff0c;主要用于打造一台巨大的超级计算机&#xff0c;马斯克称之为“超级计算工厂”。 从创立OpenAI到如今的xAI&#xff0c;技术和算力的发展历经了几个时代&#xff0c;但似乎马斯克的吸金能力一直…

CISCN --EzHeap

当时有点着急了&#xff0c;这题没写出来&#xff0c;结束后在ctfshow上做了一下。 使用的方法是environ泄露栈地址&#xff0c;然后在栈上构造orw的rop链。 以下是过程&#xff1a; 只能orw。 堆体开沙盒模式会在heap和bin一开始构造很多垃圾堆。所以分配和free的时候要注意…

nuxt3+Element Plus项目搭建过程记录

背景 本文只记录项目搭建过程中遇到的一些问题和关键点&#xff0c;nuxt框架的说明和API请参照官网学习 官网&#xff1a;https://nuxt.com/docs/getting-started/introduction 1. 初始化项目 指令如下: npx nuxilatest init <project-name>我在安装过程中出现报错&a…

玻璃加工生产线液压比例控制器

玻璃加工生产线广泛应用于自动化中空玻璃的生产、清洗、磨边、上片、除膜、打胶等各个环节&#xff0c;体现了高度的专业化和自动化水平。在玻璃制造过程中&#xff0c;液压升降机用于玻璃板材的升降和定位&#xff0c;确保玻璃在加工过程中的稳定性。液压系统提供的强大而平稳…

2024-05-28 服务器开发-不同vs版本的std::string的访问出错问题-记录

摘要: 有一个dll库是使用vs2010编译的, 使用这个dll动态库的工程是vs2019. 这个dll动态库返回一个结构体&#xff0c;其中有个成员使用了std::string。但是遇到了std::string的成员显示被赋值为NULL的情况。 本文对进行分析, 重点在于追踪问题的思路。 问题描述: dll使用vs20…

盐城市大数据集团携手百望云 以MaaS推进数字经济跃迁

随着ChatGPT的爆火&#xff0c;大模型、人工智能、大数据等技术&#xff0c;被快速推向市场最前沿。如何通过创新技术提升企业的数字化能力&#xff0c;助力数据要素资产沉淀&#xff0c;推动企业及所在行业、区域实现数智化转型&#xff0c;是大家关注的核心问题。 “携手共建…

电商API接口助力直播带货选品||助力电商平台搭建选品

如今&#xff0c;直播带货如火如荼。直播带货的核心是卖货、品牌盈利&#xff0c;那想要带货效果更好&#xff0c;选品及定价是最关键的环节。 事实上&#xff0c;品牌企业可以直接使用API接口工具来辅助自身选品及定价&#xff0c;这主要是因为比价工具在直播带货选品环节能起…

ChatGPT原创指令大全(持续更新)

随着ChatGPT在互联网上的使用越来越多&#xff0c;但很多人在使用ChatGPT的过程中会觉得得到的答案并不是很精准。究其原因其实是你给它的命令不够准确、不够到位。实际现在网上已经很多关于ChatGPT的网站&#xff0c;可以快速生成带有快捷键的ChatGPT指令。但是对于不熟悉Chat…

C++学习/复习8--STL简介/六大组件/缺陷

一、STL简介 二、六大组件 三、面试题 四、STL缺陷

前端使用JavaScript实现一个LRU缓存

引言 LRU&#xff08;Least Recently Used&#xff09;算法是一种广泛应用于内存管理和缓存系统的策略&#xff0c;在微前端、状态管理以及性能优化等场景下&#xff0c;合理使用缓存机制能够有效提升应用性能。本文将介绍LRU算法的基本原理&#xff0c;并通过JavaScript实现案…

Debian12 安装留档@Virtual Box

在学蜜罐系统的时候&#xff0c;T-Pot 需要Debian&#xff0c;于是安装Debian12 下载安装光盘 先去中科大下载了12的安装光盘&#xff0c;然后在VirtualBox中创建一个新虚拟机&#xff0c;将安装光盘挂载上。 安装光盘下载地址&#xff1a;https://mirrors.ustc.edu.cn/debi…

YOLOv8+PyQt5农作物杂草检测系统完整资源集合(yolov8模型,从图像、视频和摄像头三种路径识别检测,包含登陆页面、注册页面和检测页面)

农作物杂草检测YOLOV8(https://mbd.pub/o/bread/mbd-ZpaTl5tv)_哔哩哔哩_bilibili 资源包含可视化的农作物杂草检测系统&#xff0c;基于最新的YOLOv8训练的农作物杂草检测模型&#xff0c;和基于PyQt5制作的可视化农作物杂草检测系统&#xff0c;包含登陆页面、注册页面和检测…

手机定制开发_基于天玑900的5G安卓手机定制方案

手机定制方案基于联发科天玑900强劲旗舰八核2.4GHz处理器。这款处理器采用了6nm先进制程工艺&#xff0c;为用户带来了痛快淋漓的性能体验。不论是进行游戏还是日常娱乐&#xff0c;用户都能轻松驾驭。手机搭载了最新的Android 13操作系统&#xff0c;提高了数据读取的准确性&a…

pod容器基础概念

一 Pod基础概念&#xff1a; ①Pod是kubernetes中最小的资源管理组件&#xff0c;Pod也是最小化运行容器化应用的资源对象。一个 Pod代表着集群中运行的一个进程。一个pod包含一个或多个容器。如&#xff1a;应用容器/业务容器&#xff08;淘 宝、京东、拼多多后台&#xff…

华为机考入门python3--(32)牛客32-密码截取

分类&#xff1a;最长对称子串、动态规划 知识点&#xff1a; 生成二维数组 dp [[0] * n for _ in range(n)] 求最大值 max(value1, value2) 动态规划的步骤 a. 定义问题 长度为n下最长的对称子串的长度 b. 确定状态 dp[i][j]表示字符串从索引i到j的子串是否为对称…

ctfshow web入门 黑盒测试

web380 这里文章看的我好有感触 但是影响做题 扫描一下 访问flag.php啥也没有再访问page.php page.php?idflagweb381 扫出来page.php但是没啥用哇&#xff0c;查看源代码 这些文件挨个试发现啥也没&#xff0c;最后仔细对比发现其实都是layui&#xff0c;然后尝试着访问…

揭开 SOCKS5 有哪些强大的功能?

在在线隐私和安全领域&#xff0c;SOCKS5 是一种多功能且功能强大的协议&#xff0c;为用户提供了一种无缝的方式来加密他们的互联网流量、绕过防火墙并以增强的匿名性和灵活性访问网络。无论您是担心在线监控、地理封锁还是数据隐私&#xff0c;了解如何利用 SOCKS5 的功能都可…

远程桌面连接--“发生身份验证错误。要求的函数不受支持”

出现身份验证错误 要求的函数不受支持的问题&#xff0c;可以通过以下几种方法尝试解决&#xff1a;12 对于Windows 10家庭版用户&#xff0c;需要修改注册表信息。具体步骤如下&#xff1a; 按下WIN R&#xff0c;输入regedit&#xff0c;点击确定&#xff0c;打开注册表编辑…

基于AT89C52单片机的智能窗帘系统

点击链接获取Keil源码与Project Backups仿真图&#xff1a; https://download.csdn.net/download/qq_64505944/89276984?spm1001.2014.3001.5503 C 源码仿真图毕业设计实物制作步骤07 智能窗户控制系统学院&#xff08;部&#xff09;&#xff1a; 专 业&#xff1a; 班 级&…