Android无障碍简单开发->模拟滑动点击输入等

以下文章转载自:https://blog.csdn.net/Dullyoung/article/details/106090220

        (Android无障碍服务开发QQ群:752296312)
    似乎除了input type=password的edit text 其他所有的UI都可以进行操作。直接开始。
1
首先配置环境。
创建一个service 清单中代码如下,就算用AS直接创建,也需要配置一些权限等东西。

 <service
            android:name=".MyAccessibilityService"
            android:enabled="true"
            android:exported="true"
            android:label="@string/accessibility_service_label"
            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/accessible_service" />
        </service>

label 无障碍的名字,显示在系统辅助功能->无障碍界面的标题。权限不能掉,而且必须放在这。不能和其他权限一样放在上面。resource是无障碍服务的相关配置。xml文件如下:

//我直接写的注释 复制粘贴记得删除 不然会报错
<accessibility-service
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:accessibilityFlags="flagReportViewIds"
    android:canRetrieveWindowContent="true"
    android:notificationTimeout="100"
    android:description="@string/description"//无障碍的文字描述,展示在系统设置界面
    android:canPerformGestures="true"//允许模拟手势
    android:packageNames="com.tencent.mobileqq"/>//要检测的窗口或应用的包名

各个属性的内容和含义看这个无障碍参数详情
然后新建一个MyAccessibilityService继承AccessibilityService
重写onAccessibilityEvent()和onInterrupt()
在onAccessibilityEvent()中操作,在检测到目标包名在前台运行的时候会回调这个方法,然后我们在这获取根视图。

   try {
            //拿到根节点
            AccessibilityNodeInfo rootInfo = getRootInActiveWindow();
            if (rootInfo == null) {
                return;
            }
            //开始找目标节点,这里拎出来细讲,直接往下看正文
            if (rootInfo.getChildCount() != 0) {
                if (rootInfo == null || TextUtils.isEmpty(rootInfo.getClassName())) {
                    return;
                }
                //开始去找
                findByID(rootInfo, "com.tencent.mobileqq:id/chat_item_content_layout");
            }
        } catch (Exception e) {
            
        }

findByID方法如下:

 private void findByID(AccessibilityNodeInfo rootInfo, String text) {
        if (rootInfo.getChildCount() > 0) {
            for (int i = 0; i < rootInfo.getChildCount(); i++) {
                AccessibilityNodeInfo child = rootInfo.getChild(i);
                try {
                    if (child.findAccessibilityNodeInfosByViewId(text).size() > 0) {
                        for (AccessibilityNodeInfo info : child.findAccessibilityNodeInfosByViewId(text)) {
                            performClick(getClickable(info));
                            //模仿全局手势
//                        performGlobalAction(GLOBAL_ACTION_NOTIFICATIONS);
                        }
                    }
                } catch (NullPointerException e) {
                }
                findByID(child, text);//递归一直找一层层的全部遍历
            }
        }
    }

id通过DDMS看 

有些控件处在listview或recyclerview下,就导致id重复,所以再用text匹配。
performClick(getClickable(info));这里的一个方法。

   //有些节点不可点击 点击交给父级甚至父级的父级...来做的。
    private AccessibilityNodeInfo getClickable(AccessibilityNodeInfo info) {
        Log.i(TAG, info.getClassName() + ": " + info.isClickable());
        if (info.isClickable()) {
            return info;//如果可以点击就返回
        } else {//不可点击就检查父级 一直递归
            return getClickable(info.getParent());
        }
    }

此外通过文本内容来找到视图

  private AccessibilityNodeInfo findByText(AccessibilityNodeInfo rootInfo, String text) {
        if (rootInfo.getChildCount() > 0) {
            for (int i = 0; i < rootInfo.getChildCount(); i++) {
                AccessibilityNodeInfo child = rootInfo.getChild(i);
                try {
                    if (child.findAccessibilityNodeInfosByText(text).size() > 0) {
                        for (AccessibilityNodeInfo info : child.findAccessibilityNodeInfosByText(text)) {
                            
                                performClick(getClickable(info));
                                return null;
                            
                        }
                    }
                } catch (NullPointerException e) {
                }
                findByText(child, text);
            }
        }
        return null;

    }

找到了视图之后,就可以做各种动作,如输入框输入:

 private void changeInput(AccessibilityNodeInfo info,String text) {  //改变editText的内容
        Bundle arguments = new Bundle();
        arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,
                text);
        info.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);
    }

再如模拟手势:

    private void MyGesture(){//仿滑动
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
            Path path = new Path();
            path.moveTo(1000, 1000);//滑动起点
            path.lineTo(2000, 1000);//滑动终点
            GestureDescription.Builder builder = new GestureDescription.Builder();
            GestureDescription description = builder.addStroke(new GestureDescription.StrokeDescription(path, 100L, 100L)).build();
            //100L 第一个是开始的时间,第二个是持续时间
            dispatchGesture(description, new MyCallBack(), null);
        }
    }

模拟手势监听的回调:

  //模拟手势的监听
    @RequiresApi(api = Build.VERSION_CODES.N)
    private class MyCallBack extends GestureResultCallback {
        public MyCallBack() {
            super();
        }

        @Override
        public void onCompleted(GestureDescription gestureDescription) {
            super.onCompleted(gestureDescription);
           
        }

        @Override
        public void onCancelled(GestureDescription gestureDescription) {
            super.onCancelled(gestureDescription);
      
        }
    }

只是用无障碍可以实现点击 向上滑动 向下滑动,输入等等,左右滑动需要通过模拟手势来达到,但是模拟手势需要7.0+。
因为系统原因,无障碍服务每次运行完都得重新开启
快捷跳转 到无障碍设置界面

 Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
   startActivity(intent);

开启无障碍服务之后,再启动无障碍服务的Service

    startService(new Intent(this, MyAccessibilityService.class));

无障碍服务基本可以捕捉所有界面并点击,包括6.0+弹窗授权。
 

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Android无障碍点击是指在安卓设备中,为了帮助视障人士或有其他行动障碍的人使用设备而开发的一种功能。该功能使得用户可以通过触摸屏幕来模拟真实的点击操作。 无障碍点击功能可以通过在设备的设置中进行配置。一旦开启,用户可以使用不同的手势来模拟单击、长按、滑动、双击等操作。这些手势可以通过定义不同的触摸区域来触发不同的操作。例如,用户可以通过双击屏幕的左上角来实现返回操作,通过长按屏幕右下角来实现主屏幕操作等。 该功能对于视觉障碍的用户来说尤为重要,因为他们无法准确地通过触摸屏幕定位和点击需要的区域。而无障碍点击功能可以帮助他们通过简单的手势操作来实现他们想要的操作,从而提高他们使用设备的便利性和自主性。 除了视觉障碍的用户外,无障碍点击功能对于其他行动不便的人士也有帮助。例如,一些人可能因为手部受伤或其他身体状况而无法精确地点击屏幕。通过无障碍点击功能,他们可以通过一些简单的手势来代替真实的点击动作,从而更方便地使用设备。 总之,Android无障碍点击功能是为了帮助视障人士和其他行动有障碍的人更便捷地使用设备而设计的。这项功能可以通过简单的手势来模拟真实的点击操作,提高用户的独立性和自主性。它为广大用户创造了一个更包容和无障碍的手机环境。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值