android 辅助功能 AccessibilityService

2024-02-28 10:48

本文主要是介绍android 辅助功能 AccessibilityService,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

对于那些由于视力、听力或其它身体原因导致不能方便使用Android智能手机的用户,Android提供了Accessibility功能和服务帮助这些用户更加简单地操作设备,包括文字转语音(不支持中文)、触觉反馈、手势操作、轨迹球和手柄操作。开发者可以搭建自己的Accessibility服务,这可以加强可用性,例如声音提示,物理反馈,和其他可选的操作模式。

 

AccessibilityService官方简介:

The classes in this package are used for development of accessibility service that provide alternative or augmented feedback to the user. 
使用这个类可以开发用于给用户提供替换或者是增强反馈的辅助功能服务。

An AccessibilityService runs in the background and receives callbacks by the system when AccessibilityEvents are fired. Such events denote some state transition in the user interface, for example, the focus has changed, a button has been clicked, etc. Such a service can optionally request the capability for querying the content of the active window. Development of an accessibility service requires extends this class and implements its abstract methods. 
一个AccessibilityService在后台运行并接收系统AccessibilityEvents事件的回调,当用户界面的状态发生改变时会触发AccessibilityEvents事件,例如焦点的变化,点击一个按钮。这个服务可以获取到活动窗口的内容,开发一个辅助功能服务需要继承AccessibilityService并实现其中的抽象方法。

An AccessibilityServiceInfo describes an AccessibilityServiceInfo. The system notifies an AccessibilityService for AccessibilityEvents according to the information encapsulated in this class. 
一个AccessibilityService有一个用于描述AccessibilityService的AccessibilityServiceInfo对象,系统会通知AccessibilityService根据AccessibilityServiceInfo把信息装进AccessibilityEvents中。

继承AccessibilityService并实现其中的抽象方法。

下面是我Service类:

public class MyService extends AccessibilityService {private int code = INSTALL;private static final int INSTALL = 0;private static final int NEXT = 1;private static final int FINISH = 2;/*** 页面变化回调事件* @param event event.getEventType() 当前事件的类型;*              event.getClassName() 当前类的名称;*              event.getSource() 当前页面中的节点信息;*              event.getPackageName() 事件源所在的包名*/@Overridepublic void onAccessibilityEvent(AccessibilityEvent event) {// 事件页面节点信息不为空if (event.getSource() != null) {// 判断事件页面所在的包名,这里是自己if (event.getPackageName().equals(getApplicationContext().getPackageName())) {switch (code) {case INSTALL:click(event, "安装", TextView.class.getName());Log.d("test=======", "安装");code = NEXT;break;case NEXT:click(event, "下一步", Button.class.getName());Log.d("test=======", "下一步");code = FINISH;break;case FINISH:click(event, "完成", TextView.class.getName());Log.d("test=======", "完成");code = INSTALL;break;default:break;}}} else {Log.d("test=====", "the source = null");}}/*** 模拟点击* @param event 事件* @param text 按钮文字* @param widgetType 按钮类型,如android.widget.Button,android.widget.TextView*/private void click(AccessibilityEvent event, String text, String widgetType) {// 事件页面节点信息不为空if (event.getSource() != null) {// 根据Text搜索所有符合条件的节点, 模糊搜索方式; 还可以通过ID来精确搜索findAccessibilityNodeInfosByViewIdList<AccessibilityNodeInfo> stop_nodes = event.getSource().findAccessibilityNodeInfosByText(text);// 遍历节点if (stop_nodes != null && !stop_nodes.isEmpty()) {AccessibilityNodeInfo node;for (int i = 0; i < stop_nodes.size(); i++) {node = stop_nodes.get(i);// 判断按钮类型if (node.getClassName().equals(widgetType)) {// 可用则模拟点击if (node.isEnabled()) {node.performAction(AccessibilityNodeInfo.ACTION_CLICK);}}}}}}/*** 中断AccessibilityService的反馈时调用*/@Overridepublic void onInterrupt() {Log.d("test=====", "Interrupt");}
}

AccessibilityService里几个重要的方法:

  • onServiceConnected() - 可选。系统会在成功连接上你的服务的时候调用这个方法,在这个方法里你可以做一下初始化工作,例如设备的声音震动管理,也可以调用setServiceInfo()进行配置AccessibilityServiceInfo。
  • onAccessibilityEvent() - 必须。通过这个函数可以接收系统发送来的AccessibilityEvent,接收来的AccessibilityEvent是经过过滤的,过滤是在配置工作时设置的。
  • onInterrupt() - 必须。这个在系统想要中断AccessibilityService返给的响应时会调用。在整个生命周期里会被调用多次。
  • onUnbind() - 可选。在系统将要关闭这个AccessibilityService会被调用。在这个方法中进行一些释放资源的工作。

之后在AndroidManifest文件里注册并添加相应的权限:

<serviceandroid:name=".MyService"android:label="辅助功能"android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"><intent-filter><action android:name="android.accessibilityservice.AccessibilityService" /></intent-filter>...
</service>

配置AccessibilityService

  1. 可以在onServiceConnected()方法里进行,建立一个AccessibilityServiceInfo对象,通过这个对象设置监听系统事件类型,服务的反馈类型(震动,语音,声音),事件时间间隔,你想要监听的App的包名。最后调用setServiceInfo()进行设置,如:
 @Overrideprotected void onServiceConnected() {super.onServiceConnected();AccessibilityServiceInfo info = new AccessibilityServiceInfo();info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;info.packageNames = PACKAGE_NAMES; ...配置setServiceInfo(info);}

从Android4.0开始,开发者可以通过在AndroidManifest里添加标签配置AccessibilityService,在标签里指出配置文件的位置,如: 

res/xml/accessibility_service_info.xml
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"android:description="@string/accessibility_service_description"android:accessibilityEventTypes="typeAllMask"android:accessibilityFeedbackType="feedbackGeneric"android:notificationTimeout="100"android:accessibilityFlags="flagDefault"android:canRetrieveWindowContent="true"android:packageNames="top.cokernut.sample"android:settingsActivity="com.example.android.accessibility.ServiceSettingsActivity"  /><!--android:description="@string/accessibility_service_description" 描述android:accessibilityEventTypes="typeAllMask"  事件类型android:accessibilityFeedbackType="feedbackGeneric" 反馈类型,声音、震动等android:canRetrieveWindowContent="true", 允许获取手机页面中的信息android:packageNames="top.cokernut.sample" 要监听的包名,过滤作用android:settingsActivity="packname.android.accessibility.ServiceSettingsActivity" packname写自己App的包名-->

事件类型(EventType):

        #TYPES_ALL_MASK:所有类型#TYPE_VIEW_CLICKED :单击#TYPE_VIEW_LONG_CLICKED :长按#TYPE_VIEW_SELECTED :选中#TYPE_VIEW_FOCUSED :获取焦点#TYPE_VIEW_TEXT_CHANGED :文字改变#TYPE_WINDOW_STATE_CHANGED :窗口状态改变#TYPE_NOTIFICATION_STATE_CHANGED :通知状态改变#TYPE_VIEW_HOVER_ENTER#TYPE_VIEW_HOVER_EXIT#TYPE_TOUCH_EXPLORATION_GESTURE_START#TYPE_TOUCH_EXPLORATION_GESTURE_END#TYPE_WINDOW_CONTENT_CHANGED#TYPE_VIEW_SCROLLED#TYPE_VIEW_TEXT_SELECTION_CHANGED#TYPE_ANNOUNCEMENT#TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY#TYPE_GESTURE_DETECTION_START#TYPE_GESTURE_DETECTION_END#TYPE_TOUCH_INTERACTION_START#TYPE_TOUCH_INTERACTION_END#TYPE_WINDOWS_CHANGED

然后在AndroidManifest文件里把配置文件配置到AccessibilityService上:

<serviceandroid:name=".MyService"android:label="辅助功能"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_info" />
</service>

到此一个AccessibilityService的开发就完成了。

其他

MainActivity:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {private TextView mInstallTV;private TextView mFinishTV;private TextView mStartTV;private TextView mStopTV;private Button mInstallBT;private Button mNextBT;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mInstallTV      = (TextView) findViewById(R.id.tv_install);mStartTV        = (TextView) findViewById(R.id.tv_start);mStopTV         = (TextView) findViewById(R.id.tv_stop);mFinishTV       = (TextView) findViewById(R.id.tv_finish);mInstallBT      = (Button) findViewById(R.id.bt_install);mNextBT         = (Button) findViewById(R.id.bt_next);mInstallTV      .setOnClickListener(this);mFinishTV       .setOnClickListener(this);mInstallBT      .setOnClickListener(this);mNextBT         .setOnClickListener(this);mStartTV        .setOnClickListener(this);mStopTV         .setOnClickListener(this);}@Overrideprotected void onRestart() {super.onRestart();}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.tv_start:if (serviceIsRunning()) {showToast("服务已经在运行!");} else {startAccessibilityService();}break;case R.id.tv_stop:startActivity(new Intent(MainActivity.this, SecondActivity.class));break;case R.id.tv_install:showToast(((TextView)v).getText().toString());break;case R.id.tv_finish:showToast(((TextView)v).getText().toString());break;case R.id.bt_install:showToast(((Button)v).getText().toString());break;case R.id.bt_next:showToast(((Button)v).getText().toString());break;default:showToast("未知按钮");break;}}private void showToast(final String text) {//AccessibilityService触发事件是异步的,要回到UI线程改变UIrunOnUiThread(new Runnable() {@Overridepublic void run() {Toast.makeText(MainActivity.this, "点击了" + text, Toast.LENGTH_LONG).show();Log.d("text=====", "=====" + text);}});}/*** 判断自己的应用的AccessibilityService是否在运行** @return*/private boolean serviceIsRunning() {ActivityManager am = (ActivityManager) getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);List<ActivityManager.RunningServiceInfo> services = am.getRunningServices(Short.MAX_VALUE);for (ActivityManager.RunningServiceInfo info : services) {if (info.service.getClassName().equals(getPackageName() + ".MyService")) {return true;}}return false;}/*** 前往设置界面开启服务*/private void startAccessibilityService() {new AlertDialog.Builder(this).setTitle("开启辅助功能").setIcon(R.mipmap.ic_launcher).setMessage("使用此项功能需要您开启辅助功能").setPositiveButton("立即开启", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {// 隐式调用系统设置界面Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);startActivity(intent);}}).create().show();}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="top.cokernut.sample.MainActivity"><LinearLayoutandroid:id="@+id/activity_main"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"android:gravity="center_horizontal"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"><TextViewandroid:id="@+id/tv_install"android:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="30dp"android:background="#00AA66"android:layout_margin="10dp"android:text="安装TV" /><Buttonandroid:id="@+id/bt_install"android:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="30dp"android:text="安装Btn" /><Buttonandroid:id="@+id/bt_next"android:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="30dp"android:text="下一步Btn" /><TextViewandroid:id="@+id/tv_finish"android:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="30dp"android:background="#00AA66"android:layout_margin="10dp"android:text="完成" /><TextViewandroid:id="@+id/tv_start"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:padding="30dp"android:background="#0088FF"android:layout_margin="10dp"android:text="开始" /><TextViewandroid:id="@+id/tv_stop"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:padding="30dp"android:background="#0088FF"android:layout_margin="10dp"android:text="停止" /></LinearLayout>
</ScrollView>

这篇关于android 辅助功能 AccessibilityService的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/755285

相关文章

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

Spring框架5 - 容器的扩展功能 (ApplicationContext)

private static ApplicationContext applicationContext;static {applicationContext = new ClassPathXmlApplicationContext("bean.xml");} BeanFactory的功能扩展类ApplicationContext进行深度的分析。ApplicationConext与 BeanF

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

JavaFX应用更新检测功能(在线自动更新方案)

JavaFX开发的桌面应用属于C端,一般来说需要版本检测和自动更新功能,这里记录一下一种版本检测和自动更新的方法。 1. 整体方案 JavaFX.应用版本检测、自动更新主要涉及一下步骤: 读取本地应用版本拉取远程版本并比较两个版本如果需要升级,那么拉取更新历史弹出升级控制窗口用户选择升级时,拉取升级包解压,重启应用用户选择忽略时,本地版本标志为忽略版本用户选择取消时,隐藏升级控制窗口 2.

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目