安卓基础(无障碍)
配置无障碍服务
在 res/xml 目录下创建一个 accessibility_service_config.xml 文件,用于配置无障碍服务的相关信息,例如要监听的事件类型、反馈类型等。
<?xml version="1.0" encoding="utf-8"?>
<!-- 这行代码告诉电脑,这个文件是一个 XML 文件,用的是 1.0 版本,里面的文字是用 UTF - 8 这种编码方式写的。就好像告诉别人这本书是用什么规则写的一样。 -->
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"<!-- 这里开始定义一个无障碍服务,xmlns:android 就像是一个魔法咒语,告诉电脑接下来用到的一些特殊的词是和安卓系统有关的。 -->android:accessibilityEventTypes="typeViewClicked|typeViewFocused"<!-- 这行说的是,我们这个无障碍服务要去关注哪些事情。typeViewClicked 就是当屏幕上的东西被点击的时候,typeViewFocused 就是当屏幕上的东西被选中的时候。用 | 把它们连起来,意思是两个都要关注。 -->android:accessibilityFeedbackType="feedbackGeneric"<!-- 这行是说,当服务发现了上面说的那些事情后,要给出什么样的反馈。feedbackGeneric 就是一种通用的反馈方式。就好像你做对事情了,会得到一个通用的表扬一样。 -->android:accessibilityFlags="flagDefault"<!-- 这行设置了一些额外的小规则。flagDefault 就是用默认的那些规则。就像玩游戏用默认的游戏规则一样。 -->android:canPerformGestures="true"<!-- 这行表示这个服务能不能做出一些手势动作,比如点击、滑动等。设置成 true 就是可以做这些动作。就像你有一双可以做各种动作的小手一样。 -->android:canRetrieveWindowContent="true"<!-- 这行说的是这个服务能不能拿到屏幕上窗口里的内容。设置成 true 就是可以拿。就好像你可以看到窗户里面有什么东西一样。 -->android:description="@string/accessibility_service_description"<!-- 这行是给这个无障碍服务写一个简单的说明。@string/accessibility_service_description 是从别的地方拿过来的一段文字说明,就像给一个东西贴了一个标签,告诉别人这是什么。 -->android:notificationTimeout="100"<!-- 这行设置了一个时间,当有事情发生的时候,服务要在 100 毫秒内做出反应。就像你听到别人叫你,要在很短的时间内答应一样。 -->android:packageNames="com.example.targetapp" /><!-- 这行指定了这个无障碍服务只关注哪个应用程序。com.example.targetapp 就是那个应用的名字。就像你只关注某一个小朋友做的事情一样。 -->
在 AndroidManifest.xml 中注册服务
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.myapp"><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><serviceandroid:name=".MyAccessibilityService"android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"><intent-filter><action android:name="android.accessibilityservice.AccessibilityService" /></intent-filter><meta-dataandroid:name="android.accessibilityservice"android:resource="@xml/accessibility_service_config" /></service></application></manifest>
开始基础
// @Override 是一个特殊的标记,它告诉计算机,下面这个方法是要重写父类里的方法。就好像你要按照一个固定的模板来画画一样。
@Override
// 这是一个方法,名字叫 onAccessibilityEvent,当系统里有和无障碍相关的事情发生时,就会调用这个方法。event 就像是一个小信使,它带来了发生的事情的信息。
public void onAccessibilityEvent(AccessibilityEvent event) {// 从这个小信使(event)那里拿到事件发生的源头,也就是哪个东西上面发生了这个事件。就像知道是哪个小朋友做了某件事情一样。把这个源头存到 source 这个小盒子里。AccessibilityNodeInfo source = event.getSource();// 检查 source 这个小盒子里是不是有东西。如果没有东西,那就说明没有找到事件的源头,就不用再往下做了。if (source != null) {// 这是一个注释,告诉我们下面要做的事情是查找一个写着“点击我”的东西。// 查找要点击的视图// 在这个事件源头里,找一找有没有写着“点击我”的东西。把找到的结果存到 targetNode 这个小盒子里。AccessibilityNodeInfo targetNode = source.findAccessibilityNodeInfosByText("点击我");// 检查 targetNode 这个小盒子里是不是有东西,并且找到的东西数量要大于 0。如果满足条件,说明找到了写着“点击我”的东西。if (targetNode != null && targetNode.size() > 0) {// 从找到的那些写着“点击我”的东西里,拿出第一个。把它存到 node 这个小盒子里。AccessibilityNodeInfo node = targetNode.get(0);// 检查这个拿出来的东西是不是可以被点击。就像检查一个按钮是不是能按一样。if (node.isClickable()) {// 如果这个东西可以被点击,那就让计算机模拟点击这个动作。就像你用手指去按按钮一样。node.performAction(AccessibilityNodeInfo.ACTION_CLICK);}}}
}
- 未找到匹配元素:要是在
source对应的界面范围内,没有任何元素的文本内容是 “点击我”,那么targetNodeList会是一个空列表(即列表长度为 0)。 - 找到匹配元素:若找到了包含文本 “点击我” 的元素,
targetNodeList就会包含这些元素对应的AccessibilityNodeInfo对象。每个AccessibilityNodeInfo对象都代表一个界面元素,并且包含了该元素的各种属性和信息,像元素的位置、大小、是否可点击等。
打印 node 的结果
当你尝试打印 node 时,通常会调用 node.toString() 方法。打印的内容会包含该界面元素的一些基本信息,示例如下:
AccessibilityNodeInfo[packageName: com.example.app, className: android.widget.Button, text: 点击我, contentDescription: null, boundsInParent: Rect(0, 0 - 100, 50), boundsInScreen: Rect(100, 200 - 200, 250), childCount: 0, enabled: true, focusable: true, focused: false, clickable: true, longClickable: false, checked: false, selected: false, actions: [ACTION_CLICK]
]
找到输入框
// 引入安卓系统里和无障碍服务相关的工具包,这样我们就能使用里面的功能啦,就像打开一个装满工具的盒子。
import android.accessibilityservice.AccessibilityService;
// 引入安卓系统里和无障碍事件相关的工具包,方便我们处理各种无障碍事件,就像拿了一个专门处理事情的小本子。
import android.view.accessibility.AccessibilityEvent;
// 引入安卓系统里和无障碍节点信息相关的工具包,能让我们了解界面上各种元素的信息,就像有了一个查看元素信息的望远镜。
import android.view.accessibility.AccessibilityNodeInfo;// 定义一个公共的类,名字叫 MyAccessibilityService,这个类继承自 AccessibilityService,就像盖房子用了一个特定的房子框架。
public class MyAccessibilityService extends AccessibilityService {// 重写父类里的 onAccessibilityEvent 方法,当系统里有和无障碍相关的事件发生时,就会调用这个方法。@Overridepublic void onAccessibilityEvent(AccessibilityEvent event) {// 从事件里拿到事件发生的源头,也就是哪个界面元素上发生了这个事件,把它存到 source 这个小盒子里。AccessibilityNodeInfo source = event.getSource();// 检查 source 这个小盒子里是不是有东西,如果有东西,说明找到了事件源头。if (source != null) {// 这是一个注释,告诉我们下面要做的事情是查找一个提示文本为“请输入内容”的输入框。// 查找输入框,假设输入框的提示文本为“请输入内容”// 调用 findNodeByHintText 方法,在 source 里找提示文本是“请输入内容”的输入框,把找到的结果存到 inputNode 这个小盒子里。AccessibilityNodeInfo inputNode = findNodeByHintText(source, "请输入内容");// 检查 inputNode 这个小盒子里是不是有东西,如果有,说明找到了输入框。if (inputNode != null) {// 这是一个注释,告诉我们下面要做的事情是创建一个用来装要输入文本的包裹。// 创建一个包含要输入文本的 Bundle// 创建一个 Bundle 对象,它就像一个包裹,用来装我们要输入的文本。android.os.Bundle arguments = new android.os.Bundle();// 把要输入的文本“要输入的文本”放到这个包裹里,并且给它取个名字,名字是系统规定的一个特殊名字。arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, "要输入的文本");// 这是一个注释,告诉我们下面要做的事情是执行设置文本的操作。// 执行设置文本的操作// 让 inputNode 这个输入框执行设置文本的操作,把包裹里的文本设置进去。inputNode.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);}}}// 这是一个注释,告诉我们下面这个方法的作用是根据提示文本查找节点。// 根据提示文本查找节点// 定义一个私有的方法,名字叫 findNodeByHintText,这个方法接收两个参数,一个是根节点,一个是提示文本。private AccessibilityNodeInfo findNodeByHintText(AccessibilityNodeInfo root, String hintText) {// 检查根节点是不是为空,如果为空,说明没有东西可以找,就直接返回空。if (root == null) {return null;}// 检查根节点的提示文本是不是和我们要找的提示文本一样,如果一样,就把根节点返回。if (hintText.equals(root.getHintText())) {return root;}// 拿到根节点的子节点数量,就像知道一个大家庭里有几个小朋友。int childCount = root.getChildCount();// 用一个循环,一个一个地检查根节点的子节点。for (int i = 0; i < childCount; i++) {// 从根节点里拿出第 i 个子节点,存到 child 这个小盒子里。AccessibilityNodeInfo child = root.getChild(i);// 递归调用 findNodeByHintText 方法,在子节点里继续找符合提示文本的节点,把结果存到 result 这个小盒子里。AccessibilityNodeInfo result = findNodeByHintText(child, hintText);// 检查 result 这个小盒子里是不是有东西,如果有,说明找到了符合条件的节点,就把它返回。if (result != null) {return result;}}// 如果上面都没有找到符合条件的节点,就返回空。return null;}// 重写父类里的 onInterrupt 方法,当无障碍服务被中断时,就会调用这个方法。@Overridepublic void onInterrupt() {// 这是一个注释,告诉我们这个方法是在无障碍服务被中断时调用。// 无障碍服务被中断时调用}
}
获取输入框文本内容
import android.accessibilityservice.AccessibilityService;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;public class MyAccessibilityService extends AccessibilityService {@Overridepublic void onAccessibilityEvent(AccessibilityEvent event) {AccessibilityNodeInfo source = event.getSource();if (source != null) {// 查找输入框,假设输入框的提示文本为“请输入内容”AccessibilityNodeInfo inputNode = findNodeByHintText(source, "请输入内容");if (inputNode != null) {// 检测输入框是否已经有内容CharSequence inputText = inputNode.getText();if (inputText != null && inputText.length() > 0) {// 输入框已经有内容System.out.println("输入框已经有内容:" + inputText);} else {// 输入框没有内容,执行输入操作// 创建一个包含要输入文本的 Bundleandroid.os.Bundle arguments = new android.os.Bundle();arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, "要输入的文本");// 执行设置文本的操作inputNode.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);}}}}// 根据提示文本查找节点private AccessibilityNodeInfo findNodeByHintText(AccessibilityNodeInfo root, String hintText) {if (root == null) {return null;}if (hintText.equals(root.getHintText())) {return root;}int childCount = root.getChildCount();for (int i = 0; i < childCount; i++) {AccessibilityNodeInfo child = root.getChild(i);AccessibilityNodeInfo result = findNodeByHintText(child, hintText);if (result != null) {return result;}}return null;}@Overridepublic void onInterrupt() {// 无障碍服务被中断时调用}
}
相关文章:
安卓基础(无障碍)
配置无障碍服务 在 res/xml 目录下创建一个 accessibility_service_config.xml 文件,用于配置无障碍服务的相关信息,例如要监听的事件类型、反馈类型等。 <?xml version"1.0" encoding"utf-8"?> <!-- 这行代码告诉电脑…...
解决在linux下运行rust/tauri项目出现窗口有内容,但是渲染出来成纯黑问题
起因 最近折腾了一下rust/tauri程序开发,据说这玩意性能非常牛皮就玩了一下,但是我运行打包一直出现一个奇怪问题,窗口能正常打开,但是是纯黑的什么内容都没有,鼠标移上去又发现指针会变换(看起来是内容又…...
高性能内存kv数据库Redis(续)
目录 四.主从同步与对象模型 1.Redis 淘汰策略 2.Redis 如何做到 持久化 2.1 redis为什么要实现持久化 2.2fork进程的写时复制机制 2.3大Key的影响 2.4redis做持久化的方式 2.5 aof 2.6 rdb 2.7 redis 持久化方式的优缺点 3.redis里面的高可用体现在哪里? 3.1r…...
从0到1构建企业级消息系统服务体系(一):产品架构视角下的高并发设计与动态响应能力建设
从0到1构建企业级消息系统服务体系(一):产品架构视角下的高并发设计与动态响应能力建设 | 从今天开始将持续更新此专题下的文章,讲述从产品角度是如何从0-1的构建一个企业级的消息系统,从系统架构设计、产品架构设计&…...
ElasticSearch中常用的数据类型
一、映射 Elasticsearch中通过映射来指定字段的数据类型,映射方式有2种,静态映射和动态映射。 1.动态映射 使用动态映射时,无须指定字段的数据类型,Elasticshearch会自动根据字段内容来判断映射到哪个数据类型。 比如ÿ…...
【go】--编译
go build -o [编译完成的可执行文件] [需要编译的.go文件]#例如 go build -o myapp main.go#确保编译的结果和当前运行环境相同 #查看arch uname -a在 Linux 中查看和修改 GOOS 和 GOARCH 环境变量: 1. 查看当前 Go 环境变量 # 查看所有Go相关的环境变量 go env# …...
【指纹浏览器系列-chromium编译】
本文提供了一步一步的指导来帮助读者在Windows环境下成功编译Chromium浏览器。涵盖了系统需求、开发环境搭建、代码下载及构建等关键步骤。 官方编译文档:https://github.com/chromium/chromium/blob/main/docs/windows_build_instructions.md 一、系统要求 一台…...
Docker华为云创建私人镜像仓库
Docker华为云创建私人镜像仓库 在华为云官网的 产品 中搜索 容器镜像服务 : 或者在其他页面的搜索栏中搜索 容器镜像服务 : 进入到页面后,点击 创建组织 (华为云的镜像仓库称为组织): 设置组织名字后&…...
Ubuntu 22.04安装MySQL : Qwen2.5 模型对话数据收集与微调教程
在Ubuntu 22.04安装MySQL的教程请点击下方链接进行参考: 点击这里获取MySQL安装教程 今天将为大家带来如何微调Qwen2.5模型并连接数据库进行对话的教程。快跟着小编一起试试吧~ 1 大模型 Qwen2.5 微调步骤 1.1 从 github 仓库 克隆项目 克隆存储库:#拉取代码 git clo…...
关于 JDK 中的 jce.jar 的详解,以及与之功能类似的主流加解密工具的详细对比分析
以下是关于 JDK 中的 jce.jar 的详细解析,涵盖其作用、内容、历史背景及使用注意事项: 一、jce.jar 的核心作用 jce.jar 是 Java Cryptography Extension (JCE) 的核心实现库,提供 加密算法支持,包括: 对称加密&…...
React 更新state中的对象
更新 state 中的对象 state 中可以保存任意类型的 JavaScript 值,包括对象。但是,你不应该直接修改存放在 React state 中的对象。相反,当你想要更新一个对象时,你需要创建一个新的对象(或者将其拷贝一份)…...
【嵌入式八股4】C++:引用、模板、哈希表与 I/O
1. 左值引用与右值引用 左值与右值的定义 左值:指那些可以在表达式后取得地址的对象。换句话说,左值代表一个可以出现在赋值号()左边的值,也可以被修改。例如,变量、数组元素、以及通过引用或指针访问的对…...
算法思想之模拟
欢迎拜访:雾里看山-CSDN博客 本篇主题:算法思想之模拟 发布时间:2025.4.14 隶属专栏:算法 目录 算法介绍核心特点常见问题优化方向 例题替换所有的问号题目链接题目描述算法思路代码实现 提莫攻击题目链接题目描述算法思路代码实现…...
测试基础笔记第四天(html)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 html介绍1. 介绍2.骨架标签3.常用标签标题标签段落标签超链接标签图片标签换行和空格标签布局标签input标签(变形金刚)form标签列表标签 htm…...
WPF 中的元素继承层次结构 ,以下是对图中内容的详细说明:
顶层基类 DispatcherObject:处于继承体系最顶端,是一个抽象类。它为 WPF 元素提供了与 Dispatcher(调度器)交互的能力,Dispatcher 负责管理线程间的消息传递,确保 UI 操作在正确的线程(通常是 …...
十九、UDP编程和IO多路复用
1、UDP编程 服务端: #include<stdio.h> #include <arpa/inet.h> #include<stdlib.h> #include<string.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <pthread.h> #include &l…...
DeepSeek使用001:Word中配置DeepSeek AI的V3和R1模型
文章目录 Word中配置DeepSeek大模型1、勾选开发工具2、信任中心设置3、添加DeepSeek-V3模型4、获取API KEY5、添加DeepSeek-R1模型6、新建组7、测试使用 Word中配置DeepSeek大模型 1、勾选开发工具 打开【选项】 选择【自定义功能区】 2、信任中心设置 打开【信任中心】&…...
linux tracepoint系列宏定义(TRACE_EVENT,DEFINE_TRACE等)展开过程分析之三 define_trace.h头文件
在linux tracepoint系列宏定义(TRACE_EVENT,DEFINE_TRACE等)展开过程分析之二 文章中,我们知道trace-events-sample.h 文件在包含了tracepoint.h后第一次对TRACE_EVENT(...)等系列宏定义进行了展开,主要是构建tracepoint 调用钩子函数,注册/注销函数。展开的第二阶段…...
TDengine 与其他时序数据库对比:InfluxDB/TimescaleDB 选型指南(二)
四、应用场景分析 (一)TDengine 适用场景 TDengine 适用于对写入性能和存储效率要求极高的物联网设备数据采集场景。在一个拥有数百万个传感器的智能工厂中,每个传感器每秒都会产生多条数据,TDengine 能够高效地处理这些高并发的…...
华为OD机试真题——攀登者2(2025A卷:200分)Java/python/JavaScript/C++/C语言/GO六种最佳实现
2025 A卷 200分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C、C语言、GO六种语言的最佳实现方式! 华为OD机试真题《攀登者2》: 目录 题目名称:攀登者2…...
Windows卸载重装Docker
卸载 删除C:\Program Files\Docker ,如果更改了路径的就找到相关位置进行删除 删除 C:\Users\<用户名>\.docker 清理注册表,不然重装会报错 Exising installation is up to date 按下WindowR唤起命令输入界面,输入regedit打开注…...
JVM 为什么需要即时编译器?
JVM之所以需要即时编译器 (JIT Compiler),是为了提高 Java 程序的执行性能,弥补纯解释器执行的不足。 我们可以从以下几个角度来分析一下这个问题: 1. 解释器的性能瓶颈: 逐条解释的开销: 解释器需要逐条读取 Java 字节码指令,并…...
双目视觉中矩阵等参数说明及矫正
以下是标定文件中各个参数的详细解释: 1. 图像尺寸 (imageSize) 参数值: [1280, 1024]含义: 相机的图像分辨率,宽度为1280像素,高度为1024像素。 2. 相机内参矩阵 (leftCameraMatrix / rightCameraMatrix) 结构: yaml data: [fx, 0, cx, 0,…...
Android Compose 框架的列表与集合模块之滑动删除与拖拽深入分析(四十八)
Android Compose 框架的列表与集合模块之滑动删除与拖拽深入分析 一、引言 本人掘金号,欢迎点击关注:https://juejin.cn/user/4406498335701950 1.1 Android Compose 简介 在 Android 开发领域,界面的交互性和用户体验至关重要。传统的 A…...
一、LLM 大语言模型初窥:起源、概念与核心原理
一、初识大模型 1.1 人工智能演进与大模型兴起:从A11.0到A12.0的变迁 AI 1.0时代(2012-2022年) 感知智能的突破:以卷积神经网络(CNN)为核心,AI在图像识别、语音处理等感知任务中超越人类水平。例如&#…...
PyTorch核心函数详解:gather与where的实战指南
PyTorch中的torch.gather和torch.where是处理张量数据的关键工具,前者实现基于索引的灵活数据提取,后者完成条件筛选与动态生成。本文通过典型应用场景和代码演示,深入解析两者的工作原理及使用技巧,帮助开发者提升数据处理的灵活…...
《Operating System Concepts》阅读笔记:p636-p666
《Operating System Concepts》学习第 58 天,p636-p666 总结,总计 31 页。 一、技术总结 1.system and network threats (1)attack network traffic (2)denial of service (3)port scanning 2.symmetric/asymmetric encryption algorithm (1)symm…...
Go:接口
接口既约定 Go 语言中接口是抽象类型 ,与具体类型不同 ,不暴露数据布局、内部结构及基本操作 ,仅提供一些方法 ,拿到接口类型的值 ,只能知道它能做什么 ,即提供了哪些方法 。 func Fprintf(w io.Writer, …...
ESP32+Arduino入门(三):连接WIFI获取当前时间
ESP32内置了WIFI模块连接WIFI非常简单方便。 代码如下: #include <WiFi.h>const char* ssid "WIFI名称"; const char* password "WIFI密码";void setup() {Serial.begin(115200);WiFi.begin(ssid,password);while(WiFi.status() ! WL…...
FastAPI用户认证系统开发指南:从零构建安全API
前言 在现代Web应用开发中,用户认证系统是必不可少的功能。本文将带你使用FastAPI框架构建一个完整的用户认证系统,包含注册、登录、信息更新和删除等功能。我们将采用JWT(JSON Web Token)进行身份验证,并使用SQLite作…...
