微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

亚行无障碍重点变更 无障碍服务广播接收器通过 adb 启动服务:无障碍快捷方式

如何解决亚行无障碍重点变更 无障碍服务广播接收器通过 adb 启动服务:无障碍快捷方式

我想知道如何在 Talkback 开启时让 ADB 调整可访问性焦点。我试过了:

adb shell input trackball roll 0 1
adb shell input [stylusdpad|keyboard|mouse|touchpad|gamepad|touchnavigation|joystick|touchscreen|stylus|trackball] swipe 180 780 540 780
adb shell input keyboard keyevent KEYCODE_TAB
adb shell input keyevent KEYCODE_NAVIGATE_NEXT
adb shell "input keyevent KEYCODE_ALT_LEFT & input keyevent KEYCODE_DPAD_LEFT"

我也尝试过使用 adb shell getevent 记录事件,但没有成功播放。

但我总是必须物理滑动屏幕(即ADB 滑动不起作用)才能更改可访问性焦点。有没有办法通过可访问性来做到这一点,只是下一个和上一个动作?

我发现了这个 article by Google

导航

  • 移至下一项:Alt + 向右箭头 注意:在连续阅读模式下,此快捷方式可在文本中快进。
  • 移至上一项:Alt + 向左箭头 注意:在连续阅读模式下,此快捷方式会倒回文本。

这意味着我只需要一次发送多个按键,对吗?我试过了,based on another SO answer

device="/dev/input/event3"
ALT_KEY=57#18 #KEYCODE_ALT_LEFT
LEFT_KEY=21#37 #KEYCODE_DPAD_RIGHT
RIGHT_KEY=22#39 #KEYCODE_DPAD_RIGHT

device="/dev/input/event0"
adb shell "sendevent $device 1 $ALT_KEY 1 & sendevent $device 0 0 0 & sendevent $device 1 $RIGHT_KEY 1 & sendevent $device 0 0 0"
device="/dev/input/event1"
adb shell "sendevent $device 1 $ALT_KEY 1 & sendevent $device 0 0 0 & sendevent $device 1 $RIGHT_KEY 1 & sendevent $device 0 0 0"
device="/dev/input/event2"
adb shell "sendevent $device 1 $ALT_KEY 1 & sendevent $device 0 0 0 & sendevent $device 1 $RIGHT_KEY 1 & sendevent $device 0 0 0"
device="/dev/input/event3"
adb shell "sendevent $device 1 $ALT_KEY 1 & sendevent $device 0 0 0 & sendevent $device 1 $RIGHT_KEY 1 & sendevent $device 0 0 0"

device="/dev/input/event0"
adb shell "sendevent $device 1 $ALT_KEY 1 && sendevent $device 0 0 0 && sendevent $device 1 $RIGHT_KEY 1 && sendevent $device 0 0 0"
device="/dev/input/event1"
adb shell "sendevent $device 1 $ALT_KEY 1 && sendevent $device 0 0 0 && sendevent $device 1 $RIGHT_KEY 1 && sendevent $device 0 0 0"
device="/dev/input/event2"
adb shell "sendevent $device 1 $ALT_KEY 1 && sendevent $device 0 0 0 && sendevent $device 1 $RIGHT_KEY 1 && sendevent $device 0 0 0"
device="/dev/input/event3"
adb shell "sendevent $device 1 $ALT_KEY 1 && sendevent $device 0 0 0 && sendevent $device 1 $RIGHT_KEY 1 && sendevent $device 0 0 0"

device="/dev/input/event0"
adb shell "sendevent $device 1 $ALT_KEY 1 && sendevent $device 1 $RIGHT_KEY 1 && sendevent $device 0 0 0"
device="/dev/input/event1"
adb shell "sendevent $device 1 $ALT_KEY 1 && sendevent $device 1 $RIGHT_KEY 1 && sendevent $device 0 0 0"
device="/dev/input/event2"
adb shell "sendevent $device 1 $ALT_KEY 1 && sendevent $device 1 $RIGHT_KEY 1 && sendevent $device 0 0 0"
device="/dev/input/event3"
adb shell "sendevent $device 1 $ALT_KEY 1 && sendevent $device 1 $RIGHT_KEY 1 && sendevent $device 0 0 0"

(尽管我知道 device0 实际上是键盘设备,但我想全部尝试一下)

解决方法

我在这里的回答将尽可能简洁。我的完整代码可在 GitHub 上找到。

据我所知,开发人员无法通过 ADB 执行可访问性操作,他们必须创建一个 Accessibility service 以便 act on behalf of an Accessibility user 并创建一个 Broadcast Receiver 以便它可以通过亚行接受输入。这是答案的三分之二,还需要一个组件,因为开发人员无法通过 ADB 激活无障碍服务!必须手动每次切换可访问性或通过 accessibility shortcuts 手动完成此操作 - 其中只能有一个。 编辑我想到了这一点也出来了:)

无障碍服务

开发者文档为 Accessibility Service 提供了一种机制:

无障碍服务是一种应用,可提供用户界面增强功能,以帮助残障用户或暂时无法与设备完全交互的用户。例如,正在开车、照顾幼儿或参加非常吵闹的聚会的用户可能需要额外或替代的界面反馈。

我按照 Google Codelab 构建了一个可以对用户采取行动的服务。这是该服务的一个片段,用于左右滑动(用户导航):

    fun swipeHorizontal(leftToRight: Boolean) {
        val swipePath = Path()
        if (leftToRight) {
            swipePath.moveTo(halfWidth - quarterWidth,halfHeight)
            swipePath.lineTo(halfWidth + quarterWidth,halfHeight)
        } else {
            swipePath.moveTo(halfWidth + quarterWidth,halfHeight)
            swipePath.lineTo(halfWidth - quarterWidth,halfHeight)
        }
        val gestureBuilder = GestureDescription.Builder()
        gestureBuilder.addStroke(StrokeDescription(swipePath,500))
        dispatchGesture(gestureBuilder.build(),GestureResultCallback(baseContext),null)
    }

广播接收器。

需要注意的是,Receiver 是在服务启用时注册的:

    override fun onServiceConnected() {
        IntentFilter().apply {
            addAction(ACCESSIBILITY_CONTROL_BROADCAST_ACTION)

            priority = 100

            registerReceiver(accessibilityActionReceiver,this)           
        }
   // REMEMBER TO DEREGISTER!

然后接收者可以响应意图并调用服务:

    override fun onReceive(context: Context?,intent: Intent?) {
        require(intent != null) { "Intent is required" }
        val serviceReference = //get a reference to the service somehow

        intent.getStringExtra(ACCESSIBILITY_ACTION)?.let {
            serviceReference.apply {
                when (it) {
                    ACTION_NEXT -> swipeHorizontal(true)
                    ACTION_PREV -> swipeHorizontal(false)
                    //...

adb 上的示例用法:

adb shell am broadcast -a com.balsdon.talkback.accessibility -e ACTION "ACTION_PREV"

编辑

通过 adb 启动服务:

感谢this comment

TALKBACK="com.google.android.marvin.talkback/com.google.android.marvin.talkback.TalkBackService"
ALLYDEV="com.balsdon.accessibilityBroadcastService/.AccessibilityBroadcastService"
adb shell settings put secure enabled_accessibility_services $TALKBACK:$ALLYDEV

无障碍快捷方式

** 编辑:不再需要,但无论如何我都会把它留在这里 **

可能最烦人的事情是每次切换可访问性时,服务都会关闭。所以我在按下 VOLUME_UP 和 VOLUME_DOWN 键的情况下添加了我的 service as a shortcutThanks to this question

  INPUT_DEVICE="/dev/input/event1" # VOLUME KEYS EVENT FILE
  VOLUME_DOWN=114 #0x0072
  VOLUME_UP=115   #0x0073
  BLANK_EVENT="sendevent $INPUT_DEVICE 0 0 0"

  INST_DN="sendevent $INPUT_DEVICE 1 $VOLUME_DOWN 1 && $BLANK_EVENT && sendevent $INPUT_DEVICE 1 $VOLUME_UP 1 && $BLANK_EVENT"
  INST_UP="sendevent $INPUT_DEVICE 1 $VOLUME_DOWN 0 && $BLANK_EVENT && sendevent $INPUT_DEVICE 1 $VOLUME_UP 0 && $BLANK_EVENT"
  adb shell "$INST_DN"
  sleep 3
  adb shell "$INST_UP"

我已经有了 toggling accessibility on/off 的脚本,所以我只是在上面加上了这个,然后每次都运行我的服务。

编辑 2

我在 AOSP 上提出了一个问题,即开发人员需要编写“滑动服务”而不是“导航服务”。这是有问题的,因为可以修改手势,然后我的系统将无法按预期运行。相反,我应该能够调用我想要执行的特定操作 NAVIGATE TO NEXT ELEMENTNAVIGATE TO PREVIOUS ELEMENT,而不是“向右滑动”和“向左滑动”-阅读了 WCAG 指南后,我不相信这是违反原则。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。