通過無障礙服務(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源碼,請查看文章開頭資源鏈接。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/64681.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/64681.shtml
英文地址,請注明出處:http://en.pswp.cn/web/64681.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

java中多線程的一些常見操作

Java 中的多線程是通過并發編程來提高應用程序的效率和響應速度。Java 提供了多個機制和類來支持多線程編程&#xff0c;包括繼承 Thread 類、實現 Runnable 接口、使用線程池等。以下是 Java 中一些常見的多線程操作和應用場景。 1. 創建線程 1.1 通過繼承 Thread 類創建線程…

使用 Docker 搭建 Hadoop 集群

1.1. 啟用 WSL 與虛擬機平臺 1.1.1. 啟用功能 啟用 WSL并使用 Moba 連接-CSDN博客 1.2 安裝 Docker Desktop 最新版本鏈接&#xff1a;Docker Desktop: The #1 Containerization Tool for Developers | Docker 指定版本鏈接&#xff1a;Docker Desktop release notes | Do…

【每日學點鴻蒙知識】廣告ID、NFC手機充值、CSS支持語法、PC與模擬器交互、SO熱更新等

1、HamonyOS 樣機獲取成功返回Oaid為00000000-0000-0000-0000-000000000000&#xff1f; 請求授權時需要觸發動態授權彈窗,看一下是不是沒有觸發授權彈窗。 可以參考以下代碼以及文檔&#xff1a; // ets import identifier from ohos.identifier.oaid; import hilog from oh…

【YOLO 項目實戰】(12)紅外/可見光多模態目標檢測

歡迎關注『youcans動手學模型』系列 本專欄內容和資源同步到 GitHub/youcans 【YOLO 項目實戰】&#xff08;10&#xff09;YOLO8 環境配置與推理檢測 【YOLO 項目實戰】&#xff08;11&#xff09;YOLO8 數據集與模型訓練 【YOLO 項目實戰】&#xff08;12&#xff09;紅外/可…

logback日志框架源碼分析

目錄 (一)入口:slf4j選擇日志框架 (二)日志框架初始化 (1)logback的3種配置方式 a、BasicConfigurator默認配置 b、SPI方式配置的Configurator實現類 c、通過配置文件初始化 (2)xml配置文件初始化 (三)Logger的創建 (四)打印日志 本文源碼基于:logback版…

國產數據庫OceanBase從入門到放棄教程

1. 介紹 是由螞蟻集團&#xff08;Ant Group&#xff0c;原螞蟻金服&#xff09;自主研發的分布式關系型數據庫。它旨在解決海量數據存儲和高并發訪問的問題&#xff0c;特別適合金融級應用場景&#xff0c;如支付寶等對數據一致性、可靠性和性能有極高要求的服務。以下是關于…

連接Milvus

連接到Milvus 驗證Milvus服務器正在偵聽哪個本地端口。將容器名稱替換為您自己的名稱。 docker port milvus-standalone 19530/tcp docker port milvus-standalone 2379/tcp docker port milvus-standalone 192.168.1.242:9091/api/v1/health 使用瀏覽器訪問連接地址htt…

機器學習中的欠擬合

當模型不能夠準確地表達輸入與輸出的關系時&#xff0c;就是欠擬合。它在訓練集和未見過的數據都會產生高誤差率。過度擬合則在訓練集表現出低誤差率&#xff0c;只有對未見過的數據表現出高誤差率。 當模型太過于簡單時&#xff0c;它需要更多的訓練時間、更多的輸入特征、更…

安卓入門二 Kotlin基礎

Kotlin Kotlin的歷史 Kotlin由Jet Brains公司開發設計&#xff0c;2011年公布第一版&#xff0c;2012年開源。 2016年發布1.0正式版&#xff0c;并且Jet Brains在IDEA加入對Kotlin的支持&#xff0c;安卓自此又有新的選擇。 2019年谷歌宣布Kotlin成為安卓第一開發語言&#x…

淺談Cocos2djs逆向

前言 簡單聊一下cocos2djs手遊的逆向&#xff0c;有任何相關想法歡迎和我討論^^ 一些概念 列出一些個人認為比較有用的概念&#xff1a; Cocos遊戲的兩大開發工具分別是CocosCreator和CocosStudio&#xff0c;區別是前者是cocos2djs專用的開發工具&#xff0c;後者則是coco…

STM32驅動NRF24L01

一、NRF24L01的相關介紹 1.2 引腳的介紹 關于SPI的引腳就不再說了&#xff0c;這里介紹其余的兩個引腳&#xff1a; CE 模塊控制引腳&#xff1a;芯片開啟信號&#xff0c;激活RX或TX模式 IRQ 模塊中斷信號輸出引腳&#xff1a;其低電平有效&#xff0c;也就是中斷時變為低電平…

【Python】 glob批處理模塊的學習

1.什么是glob模塊&#xff1f; 在 Python 中&#xff0c;glob模塊是一個用于文件路徑名的模式匹配的工具。它使用簡單的通配符規則來匹配文件和目錄的路徑&#xff0c;這些通配符規則類似于在命令行中使用的文件搜索規則。這使得在處理文件系統中的多個文件或目錄時非常方便&am…

Android 系統 AlarmManager 系統層深度定制

Android 系統 AlarmManager 系統層深度定制 目錄 引言AlarmManager 概述AlarmManager 系統架構AlarmManager 核心代碼解讀AlarmManager 深度定制方法 修改 AlarmManagerService 修改定時任務調度策略增加定時任務類型定制內核層 修改定時觸發精度增加定時觸發類型優化定時任務…

解決vue-i18n在非.vue文件中,在其他js文件中無法使用的問題

其實很簡單&#xff0c;把i18n直接掛載到window上&#xff0c;全局可使用。下面請看詳細。 一、安裝 npm install vue-i18n9二、在vue的main.js中引入 import Vue from "vue" import VueI18n from vue-i18n Vue.use(VueI18n)//注入到所有的子組件&#xff0c;就是…

線性代數期末復習 [基礎篇]

關于第六點: AXB 在期末考試中一般A都是可逆的 我們可以先把A的逆求出來,X A ? 1 B A^-1B A?1B,或者 (A,B) -> r (E, A ? 1 B A^-1B A?1B) 如果A矩陣不可逆,轉變為方程組求解問題,假設都是二維矩陣 A(x1,x2) (b1,b2) Ax1 b1,Ax2 b2 XAB 如果A可逆,直接XB A ? 1 A^-…

C++ —— 數據類型轉換和數據類型的別名

數據類型轉換 引言自動類型轉換強制類型轉換數據類型的別名 引言 計算機進行運算時&#xff0c;要求各操作數的數據類型、大小和存儲方式都要相同。&#xff08;例如&#xff1a;8字節的整數和8字節的浮點數&#xff0c;雖然占用內存大小一樣&#xff0c;但是存儲方式不同&…

Kali 自動化換源腳本編寫與使用

1. 背景與需求 在使用 Kali Linux 的過程中&#xff0c;軟件源的配置對系統的更新與軟件安裝速度至關重要。 Kali 的默認官方源提供了安全且最新的軟件包&#xff0c;但有時由于網絡條件或地理位置的限制&#xff0c;使用官方源可能會出現速度較慢的問題。 為了解決這一問題&a…

設計模式-創建型-工廠方法模式

什么是工廠方法模式&#xff1f; 工廠方法模式&#xff08;Factory Method Pattern&#xff09;是 創建型設計模式之一&#xff0c;目的是通過定義一個用于創建對象的接口&#xff0c;讓子類決定實例化哪個類。簡而言之&#xff0c;工廠方法模式通過延遲對象的創建過程到子類來…

【Unity3D】ECS入門學習(十二)IJob、IJobFor、IJobParallelFor

IJob&#xff1a;開啟單個線程進行計算&#xff0c;線程內不允許對同一個數據進行操作&#xff0c;也就是如果你想用多個IJob分別計算&#xff0c;將其結果存儲到同一個NativeArray<int>數組是不允許的&#xff0c;所以不要這樣做&#xff0c;如下例子就是反面教材&#…

Spring 創建和管理 Bean 的原理,以及Spring 的單例模式是否線程安全?(有無狀態Bean)

Spring 是一個輕量級的開源框架&#xff0c;廣泛應用于 Java 企業級應用的開發。它提供了一個全面的、基于 IOC&#xff08;控制反轉&#xff09;和 AOP&#xff08;面向切面編程&#xff09;的容器&#xff0c;可以幫助開發者更好地管理應用程序中的對象。 Spring 創建和管理…