通过无障碍服务(AccessibilityService)实现Android设备全局水印显示
一、无障碍功能简介
首先我们先来了解下无障碍功能的官方介绍:
无障碍服务仅应用于帮助残障用户使用 Android 设备和应用。它们在后台运行,并在触发 AccessibilityEvents 时接收系统的回调。此类事件表示用户界面中的某些状态转换,例如焦点已更改、按钮已被点击等。此类服务可以选择性地请求查询活动窗口内容的功能。开发无障碍服务需要扩展此类并实现其抽象方法。
从以上介绍我们得知可以通过这个系统服务,添加全局的活动窗口,并对窗口状态做监听。那么我们今天就借助系统的无障碍服务来实现的设备全局水印效果,具体的需求内容是添加一个全局的文字透明层,同时确保不抢占页面焦点,并允许用户在其他应用上继续操作界面。说白了,我们要实现的全局水印效果就是实现一个顶层的透明层VIEW,只显示出来并不影响应用用户设备操作,同时给设备加水印,防止设备具体内容被剽窃,以保证达到设备安全的目的。
二、设备水印功能实现
在内容实现之前,我们先来了解一下几个Window窗口相关的属性。
窗口类型:WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY
;这种类型的窗口专门为无障碍服务设计,能覆盖在所有应用之上而不会影响用户操作。
窗口标志:WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;让窗口永远不会获得按键输入焦点,因此用户无法向其发送按键或其他按钮事件。
窗口标志:WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;让窗口永远不能接收触摸事件。此标志的目的是让位于此窗口下方的某个窗口(按 Z 顺序)来处理触摸。
窗口标志:WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;该标志可以将窗口放置在整个屏幕内,忽略来自父窗口的任何限制。
1、 创建无障碍服务
首先创建一个无障碍服务(Accessibility Service),该服务将用于显示全局的透明水印文字层。
class CustomOverlayService: AccessibilityService() {private lateinit var overlayWindowManager: WindowManagerprivate var overlayView: View? = nulloverride fun onServiceConnected() {super.onServiceConnected()// 初始化WindowManageroverlayWindowManager = getSystemService(WINDOW_SERVICE) as WindowManager// 加载布局overlayView = LayoutInflater.from(this).inflate(R.layout.layout_watermark, null)// 设置布局参数val params: WindowManager.LayoutParams = WindowManager.LayoutParams(WindowManager.LayoutParams.MATCH_PARENT,WindowManager.LayoutParams.MATCH_PARENT,WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY, // 无障碍服务专用类型WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or // 不抢占焦点WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE or // 不可触摸WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, // 显示在屏幕上PixelFormat.TRANSLUCENT)// 设置位置,例如屏幕中央params.gravity = Gravity.CENTER// 添加到WindowManageroverlayWindowManager.addView(overlayView, params)}override fun onDestroy() {super.onDestroy()if (overlayView != null) {overlayWindowManager.removeView(overlayView)}}@RequiresApi(Build.VERSION_CODES.N)override fun onAccessibilityEvent(event: AccessibilityEvent?) {// 无障碍事件处理,不做任何操作}override fun onInterrupt() {// 中断时的处理}
}
2、定义布局文件
创建显示在Window顶层的透明水印显示布局。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><LinearLayoutandroid:id="@+id/layout1"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:layout_marginTop="20dp"><TextViewandroid:layout_width="0dp"android:layout_height="100dp"android:layout_weight="1"android:gravity="center"android:rotation="50.0"android:text="Hello 2025"android:textColor="@color/light_gray"android:textSize="20sp" /><TextViewandroid:layout_width="0dp"android:layout_weight="1"android:layout_height="wrap_content"android:gravity="center"android:text="Hello 2025"android:rotation="50.0"android:textColor="@color/light_gray"android:textSize="20sp" /><TextViewandroid:layout_width="0dp"android:layout_weight="1"android:layout_height="wrap_content"android:gravity="center"android:text="Hello 2025"android:rotation="50.0"android:textColor="@color/light_gray"android:textSize="20sp" /></LinearLayout><LinearLayoutandroid:id="@+id/layout2"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:layout_marginTop="50dp"><TextViewandroid:layout_width="0dp"android:layout_height="119dp"android:layout_weight="1"android:gravity="center"android:rotation="50.0"android:text="Hello 2025"android:textColor="@color/light_gray"android:textSize="20sp" /><TextViewandroid:layout_width="0dp"android:layout_weight="1"android:layout_height="wrap_content"android:gravity="center"android:text="Hello 2025"android:rotation="50.0"android:textColor="@color/light_gray"android:textSize="20sp" /><TextViewandroid:layout_width="0dp"android:layout_weight="1"android:layout_height="wrap_content"android:gravity="center"android:text="Hello 2025"android:rotation="50.0"android:textColor="@color/light_gray"android:textSize="20sp" /></LinearLayout><LinearLayoutandroid:id="@+id/layout3"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:layout_marginTop="50dp"><TextViewandroid:layout_width="0dp"android:layout_height="119dp"android:layout_weight="1"android:gravity="center"android:rotation="50.0"android:text="Hello 2025"android:textColor="@color/light_gray"android:textSize="20sp" /><TextViewandroid:layout_width="0dp"android:layout_weight="1"android:layout_height="wrap_content"android:gravity="center"android:text="Hello 2025"android:rotation="50.0"android:textColor="@color/light_gray"android:textSize="20sp" /><TextViewandroid:layout_width="0dp"android:layout_weight="1"android:layout_height="wrap_content"android:gravity="center"android:text="Hello 2025"android:rotation="50.0"android:textColor="@color/light_gray"android:textSize="20sp" /></LinearLayout><LinearLayoutandroid:id="@+id/layout4"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:layout_marginTop="50dp"><TextViewandroid:layout_width="0dp"android:layout_height="119dp"android:layout_weight="1"android:gravity="center"android:rotation="50.0"android:text="Hello 2025"android:textColor="@color/light_gray"android:textSize="20sp" /><TextViewandroid:layout_width="0dp"android:layout_weight="1"android:layout_height="wrap_content"android:gravity="center"android:text="Hello 2025"android:rotation="50.0"android:textColor="@color/light_gray"android:textSize="20sp" /><TextViewandroid:layout_width="0dp"android:layout_weight="1"android:layout_height="wrap_content"android:gravity="center"android:text="Hello 2025"android:rotation="50.0"android:textColor="@color/light_gray"android:textSize="20sp" /></LinearLayout></LinearLayout>
3、在AndroidManifest.xml
中声明无障碍服务
在应用清单文件AndroidManifest.xml
中声明无障碍服务,并配置相关的无障碍权限。
<serviceandroid:name=".CustomOverlayService"android:exported="true"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>
另外,上面的android:resource引用的无障碍属性配置文件,需要在 res/xml/
文件夹中创建 accessibility_service_config.xml
文件,去配置无障碍服务的相关属性。
<accessibility-servicexmlns:android="http://schemas.android.com/apk/res/android"android:description="@string/accessibility_service_descriptions"android:accessibilityEventTypes="typeAllMask"android:canRetrieveWindowContent="true"android:packageNames=""android:notificationTimeout="100"android:accessibilityFeedbackType="feedbackAllMask"android:accessibilityFlags="flagDefault"android:settingsActivity=""/>
4、启用无障碍服务
写一个页面,添加一个开启无障碍服务的按钮,点击按钮跳转到系统设置中的辅助功能,可以去开启对应应用的无障碍功能开关。具体操作路径为:设置 -> 辅助功能 -> 已安装的服务
中找到你的服务并开启它。
class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)enableEdgeToEdge()setContent {Greeting()}}
}@Composable
fun Greeting() {Column(modifier = Modifier.fillMaxSize(),horizontalAlignment = Alignment.CenterHorizontally,verticalArrangement = Arrangement.Center) {val context: Context = LocalContext.currentButton(onClick = {if (!isAccessibilityServiceEnabled(context, CustomOverlayService::class.java)) {Log.i("AccessibilityService", "AccessibilityService disabled .")context.startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS))} else {Log.i("AccessibilityService", "AccessibilityService enabled .")context.startService(Intent(context,CustomOverlayService::class.java))}}, shape = ButtonDefaults.textShape) {Text(text = "启动无障碍功能")}}
}/*** 判断无障碍服务是否开启*/
private fun isAccessibilityServiceEnabled(context: Context, accessibilityServiceClass: Class<*>): Boolean {var accessibilityEnabled = 0val service: String = context.packageName.toString() + "/" + accessibilityServiceClass.canonicalNametry {accessibilityEnabled = Settings.Secure.getInt(context.contentResolver, Settings.Secure.ACCESSIBILITY_ENABLED)} catch (e: Settings.SettingNotFoundException) {e.printStackTrace()}val colonSplitter = TextUtils.SimpleStringSplitter(':')if (accessibilityEnabled == 1) {val settingValue = Settings.Secure.getString(context.contentResolver, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES)if (settingValue != null) {colonSplitter.setString(settingValue)while (colonSplitter.hasNext()) {val componentName = colonSplitter.next()if (componentName.equals(service, ignoreCase = true)) {return true}}}}return false
}
5、设备全局水印效果展示


三、总结
无障碍服务权限是一个非常强大的工具,开启后可以实现很多你意想不到的效果或者功能。比如,还可以通过无障碍服务获取设备上运行的最上层应用的包名以及VIEW。后面有空的话,我也会深挖更多的无障碍服务相关的功能来展示给大家,敬请期待!
demo源码,请查看文章开头资源链接。
相关文章:

通过无障碍服务(AccessibilityService)实现Android设备全局水印显示
一、无障碍功能简介 首先我们先来了解下无障碍功能的官方介绍: 无障碍服务仅应用于帮助残障用户使用 Android 设备和应用。它们在后台运行,并在触发 AccessibilityEvents 时接收系统的回调。此类事件表示用户界面中的某些状态转换,例如焦点已…...

flask后端开发(2):URL与视图
目录 URL定义request获取请求参数 gitcode地址: https://gitcode.com/qq_43920838/flask_project.git URL定义 from flask import FlaskappFlask(__name__)app.route(/) def hello_world():return Hello World!app.route(/profile) def profile():return 我是个人…...

力扣-数据结构-7【算法学习day.78】
前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向(例如想要掌握基础用法,该刷哪些题?建议灵神的题单和代码随想录)和记录自己的学习过程,我的解析也不会做的非常详细,只会提供思路和一些关…...

【潜意识Java】Java中深入解析抽象类与接口的差异的完整笔记总结【保姆级详细教程】
目录 一、抽象类和接口的基本概念 (一)抽象类是什么 (二)接口是什么 二、抽象类和接口的设计目的差异 (一)抽象类的设计初衷 (二)接口的设计意图 三、抽象类和接口的语法特性…...
【Flink运行时架构】系统构架
SMP架构 数据处理系统的架构最简单的实现方式就是单节点,但是随着数据量的增大,为了使单节点的机器性能更加强大,需要增加CPU数量和加大内存来提高吞吐量。这就是所谓的SMP(Symmetrical Multi Processing,对称多处理)架构。 但是这种架构带来…...

uni-ui样式修改
因为之前官网uni-ui有些组件的样式不好看,所以要做一些调整,做个记录。用分段器举例~ 官网原生样式 调整后的 首先找到我们的static文件夹,里面一般存着项目的全局样式文件,没有的话自己创一个 uniui.scss /deep/ .segmented-con…...

【linux板卡】lubancat通过vnc远程访问桌面
鲁班猫开发板通过远程VNC连接桌面: 硬件:lubancat2,网线 软件:ssh软件,vnc viewer 参考链接:https://training.eeworld.com.cn/video/38821 1、ssh连接lubancat2 ,输入ifconfig查看ip 2、输入 …...

SQLiteDataBase数据库
XML界面设计 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools"android:layout_width"match_paren…...
STM32 高级 物联网通讯之蓝牙通讯
目录 蓝牙基础知识 蓝牙概述 蓝牙产生背景 蓝牙发展历程 蓝牙技术类型 经典蓝牙(BR/EDR和AMP) 低功耗蓝牙(BLE) 市场上常见蓝牙架构 SOC蓝牙单芯片方案 SOC蓝牙+MCU方案 蓝牙host+controller分开方案 蓝牙协议栈 蓝牙芯片架构 BLE低功耗蓝牙协议栈框架 物理…...

react中实现拖拽排序
效果图:如下 效果说明: 1. 点击“选择”按钮,打开弹窗 2. 左侧数据是调接口回显来的 3. 点击左侧某条数据,这条被点击的数据就会被添加到右侧 4. 右侧的数据可以上下拖动换位置 5. 右侧有数据时,点击"确定"…...
【华为OD-E卷-AI处理器组合100分(python、java、c++、js、c)】
【华为OD-E卷-AI处理器组合100分(python、java、c、js、c)】 题目 某公司研发了一款高性能AI处理器。每台物理设备具备8颗AI处理器,编号分别为0、1、2、3、4、5、6、7。 编号0-3的处理器处于同一个链路中,编号4-7的处理器处于另…...

语音识别基础算法——动态时间规整算法
前言 动态时间规整算法,Dynamic Time Wraping,缩写为DTW,是语音识别领域的一个基础算法。 算法的提出 DTW 的提出是为了解决或尽量解决在语音识别当中的孤立词识别不正确的问题。该问题简单描述为:在识别阶段,将输入…...

模型工作流:自动化的模型内部三角面剔除
1. 关于自动减面 1.1 自动减面的重要性及现状 三维模型是游戏、三维家居设计、数字孪生、VR/AR等几乎所有三维软件的核心资产,模型的质量和性能从根本上决定了三维软件的画面效果和渲染性能。其中,模型减面工作是同时关乎质量和性能这两个要素的重要工…...
解读一个新建的 Spring Boot 项目
解读一个新建的 Spring Boot 项目。 1. 创建 Spring Boot 2.5.6 项目 步骤 1: 使用 Spring Initializr 创建项目 可以使用 Spring Initializr(https://start.spring.io/)来快速生成一个 Spring Boot 项目。 在 Spring Initializr 中选择以下配置&…...

Vue多页面路由与模版解析
上篇文章中我们成功打包并输出了多页文件,而构建一个多页应用能够让我们进一步了解项目配置的可拓展性,可以对学习 Vue 和 webpack 起到强化训练的效果,本文将在此基础上主要针对多页路由及模板的配置进行系列的介绍。 本案例代码地址&#…...

Python爬虫(二)- Requests 高级使用教程
文章目录 前言一、Session 对象1. 简介2. 跨请求保持 Cookie3. 设置缺省数据4. 方法级别参数不被跨请求保持5. 会话作为上下文管理器6. 移除字典参数中的值 二、请求与响应1. 请求与响应对象1.1 获取响应头信息1.2 获取发送到服务器的请求头信息 三、SSL 证书验证1. 忽略 SSL 证…...

并联带阻滤波器带通滤波器对幅值和相位的影响(IIR)
一、背景 输入信号input分别经过bp(带通滤波器)和bs(带阻滤波器)处理后相加输出。分析输出信号的幅值和相位受到的影响。 根据上图公式推导可知,并联滤波器对输出的影响可以直接分析,带通滤波器与带阻滤波器在频域上的加和。 二、…...

攻防世界web新手第五题supersqli
这是题目,题目看起来像是sql注入的题,先试一下最常规的,输入1,回显正常 输入1‘,显示错误 尝试加上注释符号#或者–或者%23(注释掉后面语句,使1后面的单引号与前面的单引号成功匹配就不会报错…...

vue3学习笔记(10)-$subscribe,store组合式写法
1.$subscribe订阅,监视vuex中数据得修改 2.localStorage里面穿的都是字符串,关掉浏览器数据还在 只能获取字符串,用ts语法写明,作为字符串使用 3.组合式写法...

操作系统论文导读(八):Schedulability analysis of sporadic tasks with multiple criticality specifications——具有多个
Schedulability analysis of sporadic tasks with multiple criticality specifications——具有多个关键性规范的零星任务的可调度性分析 目录 一、论文核心思想 二、基本定义 2.1 关键性指标 2.2 任务及相关参数定义 2.3 几个基础定义 三、可调度性分析 3.1 调度算法分…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...

如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...
Leetcode33( 搜索旋转排序数组)
题目表述 整数数组 nums 按升序排列,数组中的值 互不相同 。 在传递给函数之前,nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...
【安全篇】金刚不坏之身:整合 Spring Security + JWT 实现无状态认证与授权
摘要 本文是《Spring Boot 实战派》系列的第四篇。我们将直面所有 Web 应用都无法回避的核心问题:安全。文章将详细阐述认证(Authentication) 与授权(Authorization的核心概念,对比传统 Session-Cookie 与现代 JWT(JS…...