创建service
<service
android:name="com.ms.videolib.MyAccessibilityService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/accessibility_service_config" />
</service>
创建xml配置
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagDefault"
android:canPerformGestures="true"
android:canRequestTouchExplorationMode="true"
android:canRetrieveWindowContent="true"
android:description="更好的完成自动化服务,请授权使用。我们保证不滥用任何权限。每次操作界面您都可以看到"
android:notificationTimeout="100" />
无障碍回调服务:
public class MyAccessibilityService extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
Log.e("xiaoma", event.getAction() + "::处理事件");
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) {
Log.e("xiaoma", "窗体改变");
AccessibilityNodeInfo rootNode = getRootInActiveWindow();
if (rootNode != null) {
analyzeNode(rootNode);
}
}
}
private void analyzeNode(AccessibilityNodeInfo node) {
// 遍历窗口中的节点
if (node == null) return;
Rect bounds = new Rect();
node.getBoundsInScreen(bounds);
// 处理节点信息
if (!TextUtils.isEmpty(node.getText())) {
Log.d("xiaoma", "当前应用节点名称: " + node.getText() + ",当前控件中心坐标{" + bounds.centerX() + "," + bounds.centerY() + "}");
}
for (int i = 0; i < node.getChildCount(); i++) {
AccessibilityNodeInfo childNode = node.getChild(i);
analyzeNode(childNode);
if (childNode != null) {
childNode.recycle(); // 回收节点,防止内存泄漏
}
}
}
@Override
public void onInterrupt() {
// 处理中断
}
// 模拟点击事件
public void performClick(float x, float y) {
Path path = new Path();
path.moveTo(x, y);
GestureDescription.Builder builder = new GestureDescription.Builder();
GestureDescription.StrokeDescription strokeDescription = new GestureDescription.StrokeDescription(path, 0, 100);
builder.addStroke(strokeDescription);
dispatchGesture(builder.build(), new GestureResultCallback() {
@Override
public void onCompleted(GestureDescription gestureDescription) {
super.onCompleted(gestureDescription);
Log.d("AccessibilityService", "当前点击事件执行成功");
}
@Override
public void onCancelled(GestureDescription gestureDescription) {
super.onCancelled(gestureDescription);
Log.d("AccessibilityService", "点击事件取消");
}
}, new Handler(Looper.getMainLooper()));
}
// 模拟双击事件
public void performDoubleClick(float x, float y) {
performClick(x, y); // 第一次点击
new Handler(Looper.getMainLooper()).postDelayed(() -> performClick(x, y), 200); // 第二次点击,延迟200毫秒
}
// 模拟滑动事件
public void performSwipe(float startX, float startY, float endX, float endY, long duration) {
Path path = new Path();
path.moveTo(startX, startY);
path.lineTo(endX, endY);
GestureDescription.StrokeDescription stroke = new GestureDescription.StrokeDescription(path, 0, duration);
GestureDescription.Builder builder = new GestureDescription.Builder();
builder.addStroke(stroke);
dispatchGesture(builder.build(), null, null);
}
}
常用的窗体事件:
常用的 AccessibilityEvent 类型
TYPE_VIEW_CLICKED:
当用户点击视图时生成。
TYPE_VIEW_LONG_CLICKED:
当用户长按视图时生成。
TYPE_VIEW_SELECTED:
当视图被选择时生成,比如选择下拉菜单中的一个选项。
TYPE_VIEW_FOCUSED:
当视图获得焦点时生成。
TYPE_VIEW_TEXT_CHANGED:
当视图中的文本内容发生变化时生成。
TYPE_VIEW_TEXT_SELECTION_CHANGED:
当视图中文本的选择范围发生变化时生成。
TYPE_VIEW_SCROLLED:
当视图滚动时生成。
TYPE_WINDOW_STATE_CHANGED:
当窗口的状态(如窗口的活动状态或窗口布局的改变)发生变化时生成。
TYPE_NOTIFICATION_STATE_CHANGED:
当通知栏中的通知发生变化时生成。
TYPE_TOUCH_EXPLORATION_GESTURE_START:
当触摸探索手势开始时生成。
TYPE_TOUCH_EXPLORATION_GESTURE_END:
当触摸探索手势结束时生成。
TYPE_ANNOUNCEMENT:
用于宣布重要的应用信息,如无障碍提示。
TYPE_WINDOW_CONTENT_CHANGED:
当窗口内容发生变化时生成,常用于检测动态更新的 UI 元素。
TYPE_VIEW_HOVER_ENTER 和 TYPE_VIEW_HOVER_EXIT:
当鼠标悬停进入或离开视图时生成。
TYPE_VIEW_ACCESSIBILITY_FOCUSED 和 TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED:
当视图获得或失去无障碍焦点时生成。
检测是否开启无障碍服务
public static boolean isAccessibilityServiceEnabled(Context context, Class<? extends AccessibilityService> service) {
ComponentName expectedComponentName = new ComponentName(context, service);
String enabledServicesSetting = Settings.Secure.getString(
context.getContentResolver(),
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES
);
final TextUtils.SimpleStringSplitter colonSplitter = new TextUtils.SimpleStringSplitter(':');
colonSplitter.setString(enabledServicesSetting);
while (colonSplitter.hasNext()) {
final String componentName = colonSplitter.next();
if (componentName.equalsIgnoreCase(expectedComponentName.flattenToString())) {
return true;
}
}
return false;
}
未开启的话跳转到设置开启服务:
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
startActivity(intent);