一、无障碍功能简介
首先我们先来了解下无障碍功能的官方介绍:
无障碍服务仅应用于帮助残障用户使用 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: WindowManager
private var overlayView: View? = null
override fun onServiceConnected() {
super.onServiceConnected()
// 初始化WindowManager
overlayWindowManager = 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
// 添加到WindowManager
overlayWindowManager.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顶层的透明水印显示布局。
<?