亚行可访问性焦点变化

Qui*_*don 5 android accessibility talkback

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

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"
Run Code Online (Sandbox Code Playgroud)

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

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

我在谷歌找到了这篇文章

导航

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

这意味着我只需要一次发送多个按键,对吗?我尝试了这个,基于另一个 SO 答案

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"
Run Code Online (Sandbox Code Playgroud)

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

Qui*_*don 2

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

据我所知,开发人员无法通过 ADB 执行辅助功能操作,他们必须创建一个辅助功能服务才能代表辅助功能用户进行操作,并创建一个广播接收器,以便它可以通过 ADB 获取输入。这是答案的三分之二,还需要一个组件,因为开发人员无法通过 ADB 激活辅助功能服务!每次切换可访问性时都必须手动完成此操作,或者通过可访问性快捷方式(其中只能有一个)完成。 编辑我也想出了这一点:)

无障碍服务

开发人员文档提供了一种辅助服务机制:

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

我按照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, 0, 500))
        dispatchGesture(gestureBuilder.build(), GestureResultCallback(baseContext), null)
    }
Run Code Online (Sandbox Code Playgroud)

广播接收器。

需要注意的是,接收器是在启用服务时注册的:

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

            priority = 100

            registerReceiver(accessibilityActionReceiver, this)           
        }
   // REMEMBER TO DEREGISTER!
Run Code Online (Sandbox Code Playgroud)

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

    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)
                    //...
Run Code Online (Sandbox Code Playgroud)

adb 上的用法示例:

adb shell am broadcast -a com.balsdon.talkback.accessibility -e ACTION "ACTION_PREV"
Run Code Online (Sandbox Code Playgroud)

编辑

通过adb启动服务:

感谢这个评论

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
Run Code Online (Sandbox Code Playgroud)

辅助功能快捷方式

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

也许最烦人的事情是每次切换可访问性时,服务都会关闭。因此,我将服务添加为按下 VOLUME_UP 和 VOLUME_DOWN 键的快捷方式。感谢这个问题

  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"
Run Code Online (Sandbox Code Playgroud)

我已经有一个用于打开/关闭可访问性的脚本,所以我只是将其添加到该脚本之上,这样我的服务每次都会运行。

编辑2

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