项目demo地址,demo_accessibility目录下;
https://gitee.com/catface7/catface_app
核心服务lib模块
-
res>xml>accessibility_config.xml
<?xml version="1.0" encoding="utf-8"?> <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityEventTypes="typeAllMask" android:accessibilityFeedbackType="feedbackGeneric" android:accessibilityFlags="flagReportViewIds|flagRetrieveInteractiveWindows|flagRequestFilterKeyEvents" android:canPerformGestures="true" android:canRequestFilterKeyEvents="true" android:canRetrieveWindowContent="true" android:description="@string/accessibility_description" android:notificationTimeout="100" />
-
res>values>strings.xml
<resources> <string name="accessibility_description">辅助功能测试</string> </resources>
-
AndroidManifest.xml中声明无障碍服务
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cc.catface.accessibility"> <application> <service android:name=".ProAccessibilityService" android:enabled="true" android:exported="true" 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_config" /> </service> </application> </manifest>
-
服务启动帮助类AccessibilitySettingOpenHelper
import android.app.ActivityManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.provider.Settings; import java.util.List; public class AccessibilitySettingOpenHelper { //跳转到开启无障碍设置页面 public static void jumpToSettingPage(Context context) { Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); } //判断自定义辅助功能服务是否开启 public static boolean isAccessibilitySettingsOn(Context context, String className) { if (context == null) return false; ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); if (activityManager == null) return false; //判断当前无障碍服务是否在运行服务列表中 List<ActivityManager.RunningServiceInfo> runningServices = activityManager.getRunningServices(100); runningServices.size(); for (int i = 0; i < runningServices.size(); i++) { ComponentName service = runningServices.get(i).service; if (service.getClassName().equals(className)) { return true; } } return false; } }
-
核心服务类ProAccessibilityService,包含根据id,文本内容,描述内容查找控件,模拟控件点击,绝对位置点击等功能;
import android.accessibilityservice.AccessibilityService; import android.accessibilityservice.GestureDescription; import android.annotation.SuppressLint; import android.graphics.Path; import android.graphics.Rect; import android.os.CountDownTimer; import android.text.TextUtils; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; /** * 无障碍 * rootNode.findAccessibilityNodeInfosByViewId(id): 根据详细id查找控件 * rootNode.findAccessibilityNodeInfosByText(text): 根据文本内容查找控件 */ public class ProAccessibilityService extends AccessibilityService { private static final String TAG = "ProAccessibilityService"; private static ProAccessibilityService instance; public static ProAccessibilityService getInstance() { return instance; } //仅根据具体id/文本内容/描述查找控件|全开 private boolean findByIdEnabled, findByTextEnabled, findByDescEnabled, findByAllEnabled; private int textMatchType = 0, descMatchType = 0;//0完全匹配1部分匹配2开头匹配3结尾匹配 private FindByIdCallback findByIdCallback; private FindByTextCallback findByTextCallback; private FindByDescCallback findByDescCallback; private int[] clickId, clickText, clickDesc;//[0,0,1,1000](p1:0开启点击1关闭点击|p2:点击第几个控件|p3:每次点击前延时) private CountDownTimer idTimer, textTimer, descTimer; public void setClickId(int[] clickId) { releaseAllTimer(); this.clickId = clickId; } public void setClickText(int[] clickText) { releaseAllTimer(); this.clickText = clickText; } public void setClickDesc(int[] clickDesc) { releaseAllTimer(); if (originNodeByDesc != null) originNodeByDesc.clear(); this.clickDesc = clickDesc; } public interface FindByIdCallback { //原始节点集合;封装的节点集合 void byIdResult(List<AccessibilityNodeInfo> originNodes, List<NodeInfo> nodeInfos); } public interface FindByTextCallback { //原始节点集合;封装的节点集合 void byTextResult(List<AccessibilityNodeInfo> originNodes, List<NodeInfo> nodeInfos); } public interface FindByDescCallback { //原始节点集合;封装的节点集合 void byDescResult(List<AccessibilityNodeInfo> originNodes, List<NodeInfo> nodeInfos); } //id/文本内容/描述 private String id, text, desc; public void setFindByAllEnabled() { this.findByIdEnabled = true; this.findByTextEnabled = true; this.findByDescEnabled = true; } public void setFindByIdEnabled(FindByIdCallback callback) { this.findByIdEnabled = true; this.findByTextEnabled = false; this.findByDescEnabled = false; this.findByIdCallback = callback; } public void setFindByTextEnabled(FindByTextCallback callback) { this.findByIdEnabled = false; this.findByTextEnabled = true; this.findByDescEnabled = false; this.findByTextCallback = callback; } public void setFindByDescEnabled(FindByDescCallback callback) { this.findByIdEnabled = false; this.findByTextEnabled = false; this.findByDescEnabled = true; this.findByDescCallback = callback; } public void setId(String id) { this.id = id; } public void setTextAndFilterType(String text, int type) { this.text = text; this.textMatchType = type; } public void setDescAndFilterType(String desc, int type) { this.desc = desc; this.descMatchType = type; } @Override//服务初始化连接 protected void onServiceConnected() { super.onServiceConnected(); instance = this; } //原始节点信息转换目标节点信息 private List<NodeInfo> getTransNodes(List<AccessibilityNodeInfo> originNodes) { List<NodeInfo> nodeInfos = new ArrayList<>(); for (AccessibilityNodeInfo n : originNodes) { if (n.getText() == null) return new ArrayList<>(); NodeInfo info = new NodeInfo(); info.setViewIdResourceName(n.getViewIdResourceName()); info.setText(n.getText()); info.setContentDescription(n.getContentDescription()); info.setClassName(n.getClassName()); info.setPackageName(n.getPackageName()); info.setChildCount(n.getChildCount()); Rect rectInScreen = new Rect(); n.getBoundsInScreen(rectInScreen); info.setBoundsInScreen(new int[]{rectInScreen.left, rectInScreen.top, rectInScreen.right, rectInScreen.bottom}); Rect rectInParent = new Rect(); n.getBoundsInParent(rectInParent); info.setBoundsInParent(new int[]{rectInParent.left, rectInParent.top, rectInParent.right, rectInParent.bottom}); info.setClickable(n.isClickable()); nodeInfos.add(info); } return nodeInfos; } private List<AccessibilityNodeInfo> originNodeByDesc; @SuppressLint("NewApi") private void iteratorNode(AccessibilityNodeInfo rootNode) { if (rootNode.getChildCount() != 0) { for (int i = 0; i < rootNode.getChildCount(); i++) { AccessibilityNodeInfo child = rootNode.getChild(i); if (child.getChildCount() != 0) { iteratorNode(child); } originNodeByDesc.add(child); } } } /*显示节点信息*/ private void showNodesInfo(String byWhat, List<AccessibilityNodeInfo> nodes) { if (nodes == null || nodes.size() < 1) return; int size = nodes.size(); for (int i = 0; i < nodes.size(); i++) { AccessibilityNodeInfo child = nodes.get(i); TLog.d(TAG, "===通过" + byWhat + "查找的节点结果, 第" + (i + 1) + "/" + size + "个", "id:" + child.getViewIdResourceName() + ", 类:" + child.getClassName() + ", 文本:" + child.getText() + ", 描述:" + child.getContentDescription()); } } private List<AccessibilityNodeInfo> originNodesByText; private AccessibilityNodeInfo mClickNodeById; private AccessibilityNodeInfo mClickNodeByText; private AccessibilityNodeInfo mClickNodeByDesc; @SuppressLint("NewApi") @Override public void onAccessibilityEvent(AccessibilityEvent event) { if (event == null) return; //TLog.d(getClass().getSimpleName(), "=>进入无障碍核心回调onAccessibilityEvent(), packageName:" + event.getPackageName() + ", eventType:" + event.getEventType() + ", idTimer:" + idTimer + ", textTimer:" + textTimer + ", descTimer:" + descTimer); AccessibilityNodeInfo rootNode = getRootInActiveWindow(); if (rootNode == null) return; //根据id查找 if (this.findByIdEnabled && this.id != null && !TextUtils.isEmpty(this.id) && this.findByIdCallback != null) { TLog.d(TAG, "====================>开始通过id[" + id + "]&clickId[" + Arrays.toString(clickId) + "]查找节点"); final List<AccessibilityNodeInfo> originNodesById = rootNode.findAccessibilityNodeInfosByViewId(this.id); showNodesInfo("id", originNodesById);//打印结果 this.findByIdCallback.byIdResult(originNodesById, getTransNodes(originNodesById)); //点击事件 if (this.clickId != null && this.clickId.length == 3 && this.clickId[0] == 0 && this.clickId[1] < originNodesById.size()) { int clickNodeIndex = this.clickId[1];//第几个控件 int intervalMillis = this.clickId[2];//延时(ms) mClickNodeById = originNodesById.get(clickNodeIndex); if (idTimer == null) { idTimer = new CountDownTimer(Integer.MAX_VALUE, intervalMillis) { @Override public void onTick(long l) { performClick(mClickNodeById); } @Override public void onFinish() {} }; idTimer.start(); } } } //根据text查找 if (this.findByTextEnabled && this.text != null && !TextUtils.isEmpty(this.text) && this.findByTextCallback != null) { TLog.d(TAG, "====================>开始通过text[" + text + "]&clickText[" + Arrays.toString(clickText) + "]查找节点"); originNodesByText = rootNode.findAccessibilityNodeInfosByText(this.text);//根据文本内容查找控件 //根据文本内容匹配规则过滤[0完全匹配1部分匹配2开头匹配3结尾匹配] if (originNodesByText == null || originNodesByText.size() < 1) { this.findByTextCallback.byTextResult(new ArrayList<>(), new ArrayList<>()); } else { originNodesByText = originNodesByText.stream().filter(accessibilityNodeInfo -> accessibilityNodeInfo.getText() != null).collect(Collectors.toList()); if (this.textMatchType == 0) { originNodesByText = originNodesByText.stream().filter(accessibilityNodeInfo -> accessibilityNodeInfo.getText().toString().equals(this.text)).collect(Collectors.toList()); } else if (this.textMatchType == 1) { originNodesByText = originNodesByText.stream().filter(accessibilityNodeInfo -> accessibilityNodeInfo.getText().toString().contains(this.text)).collect(Collectors.toList()); } else if (this.textMatchType == 2) { originNodesByText = originNodesByText.stream().filter(accessibilityNodeInfo -> accessibilityNodeInfo.getText().toString().startsWith(this.text)).collect(Collectors.toList()); } else if (this.textMatchType == 3) { originNodesByText = originNodesByText.stream().filter(accessibilityNodeInfo -> accessibilityNodeInfo.getText().toString().endsWith(this.text)).collect(Collectors.toList()); } showNodesInfo("text", originNodesByText);//打印结果 this.findByTextCallback.byTextResult(originNodesByText, getTransNodes(originNodesByText)); } //点击事件 if (this.clickText != null && this.clickText.length == 3 && this.clickText[0] == 0 && this.clickText[1] < originNodesByText.size()) { int clickNodeIndex = this.clickText[1];//第几个控件 int intervalMillis = this.clickText[2];//延时(ms) //判断这个控件是否可点 mClickNodeByText = originNodesByText.get(clickNodeIndex); if (textTimer == null) { textTimer = new CountDownTimer(Integer.MAX_VALUE, intervalMillis) { @Override public void onTick(long l) { performClick(mClickNodeByText); } @Override public void onFinish() {} }; textTimer.start(); } } } if (this.findByDescEnabled && this.desc != null && !TextUtils.isEmpty(this.desc) && this.findByDescCallback != null) { TLog.d(getClass().getSimpleName(), "====================>开始通过desc[" + desc + "]&clickDesc[" + Arrays.toString(clickDesc) + "]查找节点"); //遍历所有控件 originNodeByDesc = new ArrayList<>(); iteratorNode(rootNode); //打印遍历的页面所有节点信息 showNodesInfo("desc[原始]", originNodeByDesc); if (originNodeByDesc == null || originNodeByDesc.size() < 1) { this.findByDescCallback.byDescResult(new ArrayList<>(), new ArrayList<>()); } else { originNodeByDesc = originNodeByDesc.stream().filter(accessibilityNodeInfo -> accessibilityNodeInfo.getContentDescription() != null).collect(Collectors.toList()); if (this.descMatchType == 0) { originNodeByDesc = originNodeByDesc.stream().filter(accessibilityNodeInfo -> accessibilityNodeInfo.getContentDescription().toString().equals(this.desc)).collect(Collectors.toList()); } else if (this.descMatchType == 1) { originNodeByDesc = originNodeByDesc.stream().filter(accessibilityNodeInfo -> accessibilityNodeInfo.getContentDescription().toString().contains(this.desc)).collect(Collectors.toList()); } else if (this.descMatchType == 2) { originNodeByDesc = originNodeByDesc.stream().filter(accessibilityNodeInfo -> accessibilityNodeInfo.getContentDescription().toString().startsWith(this.desc)).collect(Collectors.toList()); } else if (this.descMatchType == 3) { originNodeByDesc = originNodeByDesc.stream().filter(accessibilityNodeInfo -> accessibilityNodeInfo.getContentDescription().toString().endsWith(this.desc)).collect(Collectors.toList()); } showNodesInfo("desc[过滤]", originNodeByDesc);//打印信息 this.findByDescCallback.byDescResult(originNodeByDesc, getTransNodes(originNodeByDesc)); } //点击事件 if (this.clickDesc != null && this.clickDesc.length == 3 && this.clickDesc[0] == 0 && this.clickDesc[1] < originNodeByDesc.size()) { int clickNodeIndex = this.clickDesc[1];//第几个控件 int intervalMillis = this.clickDesc[2];//延时(ms) mClickNodeByDesc = originNodeByDesc.get(clickNodeIndex); if (descTimer == null) { descTimer = new CountDownTimer(Integer.MAX_VALUE, intervalMillis) { @Override public void onTick(long l) { performClick(mClickNodeByDesc); } @Override public void onFinish() {} }; descTimer.start(); } } //一次全页面搜索控件结束后清空暂存的控件列表 if (originNodeByDesc != null) { originNodeByDesc.clear(); originNodeByDesc = null; } } } @Override public void onInterrupt() { releaseAllTimer(); instance = null; TLog.d(TAG, "onInterrupt()"); } @Override public void onDestroy() { super.onDestroy(); releaseAllTimer(); instance = null; TLog.d(TAG, "onDestroy()"); } private void releaseAllTimer() { if (idTimer != null) { idTimer.cancel(); idTimer = null; } if (textTimer != null) { textTimer.cancel(); textTimer = null; } if (descTimer != null) { descTimer.cancel(); descTimer = null; } } //当前服务是否正在运行 public static boolean isRunning() { return instance != null; } //模拟点击-绝对坐标 @SuppressLint("NewApi") public void performClickAbsXY(int x, int y) { Path path = new Path(); path.moveTo(x - 1, y - 1); path.lineTo(x + 1, y + 1); TLog.d(TAG, "模拟点击=>performClickAbsXY()=绝对坐标, x:" + x + ", y:" + y); dispatchGesture(new GestureDescription.Builder().addStroke(new GestureDescription.StrokeDescription(path, 0, 100)).build(), null, null); } //模拟点击-控件 private void performClick(AccessibilityNodeInfo... nodes) { if (nodes == null || nodes.length < 1) return; for (AccessibilityNodeInfo node : nodes) { if (!node.isClickable()) continue; TLog.d(TAG, "模拟点击=>performClick()=控件, id:" + node.getViewIdResourceName() + ", text:" + node.getText()); node.performAction(AccessibilityNodeInfo.ACTION_CLICK); } } //模拟点击-返回 @SuppressWarnings("all") public boolean performClickBackKey() { TLog.d(TAG, "模拟点击=>performClickBackKey()=点击"); return performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK); } }
-
简化的节点信息包装实例NodeInfo
public class NodeInfo { private String viewIdResourceName;//app.catface.accessibility:id/bt1 private CharSequence text; private CharSequence contentDescription; private CharSequence className;//android.widget.Button private CharSequence packageName;//包名 private int childCount;//子控件个数 private int[] boundsInScreen;//屏幕位置 private int[] boundsInParent;//父布局位置 private boolean isClickable; }
-
日志打印Tlog
public class TLog { public static final String DEFAULT_TAG = "accessibility-test"; public static void d(String className, String msg) { d(DEFAULT_TAG, className, msg); } public static void d(String tag, String className, String msg) { Log.d(tag, "[" + className + "]" + msg); } }
调用示例app模块
-
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.appcompat.widget.LinearLayoutCompat 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" android:orientation="vertical" tools:context=".MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/btStartService" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginHorizontal="20dp" android:layout_weight="1" android:text="开启服务" /> <Button android:id="@+id/btStopService" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginHorizontal="20dp" android:layout_weight="1" android:text="关闭服务" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <EditText android:id="@+id/etDestId" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="3" android:hint="控件id" android:text="app.catface.accessibility:id/bt1" /> <Button android:id="@+id/btSearchId" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="搜索" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <EditText android:id="@+id/etText" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="3" android:hint="节点内容" android:text="试试" /> <EditText android:id="@+id/etTextMatchType" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:hint="0123" android:text="1" /> <Button android:id="@+id/btSearchText" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="搜索" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <EditText android:id="@+id/etDesc" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="3" android:hint="描述内容" android:text="试试" /> <EditText android:id="@+id/etDescMatchType" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:hint="0123" android:text="1" /> <Button android:id="@+id/btSearchDesc" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="搜索" /> </LinearLayout> <Button android:id="@+id/btClearClick" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="取消点击事件" /> <Button android:id="@+id/bt2Page2" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="跳转到第二页" /> <Button android:id="@+id/btStartClick" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="开启自由点击" /> <Button android:id="@+id/btClickBack" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="模拟返回" /> </androidx.appcompat.widget.LinearLayoutCompat>
-
MainActivity.java
import android.content.Intent; import android.os.Build; import android.os.Bundle; import android.os.CountDownTimer; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.EditText; import android.widget.Toast; import androidx.annotation.RequiresApi; import androidx.appcompat.app.AppCompatActivity; import java.util.List; import cc.catface.accessibility.AccessibilitySettingOpenHelper; import cc.catface.accessibility.NodeInfo; import cc.catface.accessibility.ProAccessibilityService; import cc.catface.accessibility.TLog; public class MainActivity extends AppCompatActivity implements ProAccessibilityService.FindByIdCallback, ProAccessibilityService.FindByTextCallback, ProAccessibilityService.FindByDescCallback { @RequiresApi(api = Build.VERSION_CODES.N) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //开启无障碍服务 findViewById(R.id.btStartService).setOnClickListener(v -> { if (!AccessibilitySettingOpenHelper.isAccessibilitySettingsOn(this, ProAccessibilityService.class.getName())) { AccessibilitySettingOpenHelper.jumpToSettingPage(this); } else { Toast.makeText(this, "无障碍服务已开启", Toast.LENGTH_SHORT).show(); } }); //关闭无障碍服务 findViewById(R.id.btStopService).setOnClickListener(v -> { ProAccessibilityService.getInstance().disableSelf(); }); //跳转到第二页 findViewById(R.id.bt2Page2).setOnClickListener(v -> { startActivity(new Intent(this, SecondActivity.class)); }); //设置搜索指定控件id findViewById(R.id.btSearchId).setOnClickListener(v -> { String id = ((EditText) findViewById(R.id.etDestId)).getText().toString(); ProAccessibilityService.getInstance().setId(id);//指定控件id如:app.catface.accessibility:id/bt1 ProAccessibilityService.getInstance().setFindByIdEnabled(this);//回调结果 ProAccessibilityService.getInstance().setClickId(new int[]{0, 0, 3000});//点击:p1=0开启点击;p2=0点击第几个控件;p3点击延时 }); //设置搜索内容text findViewById(R.id.btSearchText).setOnClickListener(v -> { String text = ((EditText) findViewById(R.id.etText)).getText().toString(); String typeStr = ((EditText) findViewById(R.id.etTextMatchType)).getText().toString(); //text:文本内容;p2匹配类型[0完全匹配1部分匹配2开头匹配3结尾匹配] ProAccessibilityService.getInstance().setTextAndFilterType(text, Integer.parseInt(typeStr)); ProAccessibilityService.getInstance().setFindByTextEnabled(this);//回调结果 ProAccessibilityService.getInstance().setClickText(new int[]{0, 0, 3000});//点击:p1=0开启点击;p2=0点击第几个控件;p3点击延时 }); //设置搜索描述desc findViewById(R.id.btSearchDesc).setOnClickListener(v -> { String desc = ((EditText) findViewById(R.id.etDesc)).getText().toString(); String typeStr = ((EditText) findViewById(R.id.etDescMatchType)).getText().toString(); //desc:描述内容;p2匹配类型[0完全匹配1部分匹配2开头匹配3结尾匹配] ProAccessibilityService.getInstance().setDescAndFilterType(desc, Integer.parseInt(typeStr)); ProAccessibilityService.getInstance().setFindByDescEnabled(this);//回调结果 ProAccessibilityService.getInstance().setClickDesc(new int[]{0, 0, 3000});//点击:p1=0开启点击;p2=0点击第几个控件;p3点击延时 }); //清空模拟点击 findViewById(R.id.btClearClick).setOnClickListener(v -> { ProAccessibilityService.getInstance().setClickId(null);//清空模拟点击 ProAccessibilityService.getInstance().setClickText(null);//清空模拟点击 ProAccessibilityService.getInstance().setClickDesc(null);//清空模拟点击 }); //模拟点击绝对位置 findViewById(R.id.btStartClick).setOnClickListener(v -> { new CountDownTimer(2000, 2000) { @Override public void onTick(long millisUntilFinished) {} @Override public void onFinish() { ProAccessibilityService.getInstance().performClickAbsXY(5, 85); } }.start(); }); //模拟返回 findViewById(R.id.btClickBack).setOnClickListener(v -> { new CountDownTimer(2000, 2000) { @Override public void onTick(long millisUntilFinished) {} @Override public void onFinish() { ProAccessibilityService.getInstance().performClickBackKey(); } }.start(); }); } @Override public void byIdResult(List<AccessibilityNodeInfo> originNodes, List<NodeInfo> nodeInfos) { for (NodeInfo info : nodeInfos) { TLog.d(getClass().getSimpleName(), "IDID节点#RESULT:" + info.toString()); } } @Override public void byTextResult(List<AccessibilityNodeInfo> originNodes, List<NodeInfo> nodeInfos) { for (NodeInfo info : nodeInfos) { TLog.d(getClass().getSimpleName(), "TEXT内容#RESULT:" + info.toString()); } } @Override public void byDescResult(List<AccessibilityNodeInfo> originNodes, List<NodeInfo> nodeInfos) { for (NodeInfo info : nodeInfos) { TLog.d(getClass().getSimpleName(), "DESC描述#RESULT:" + info.toString()); } } }