实施 Fire OS 辅助功能


实施 Fire OS 辅助功能

本页讨论与实施 Fire OS 辅助功能相关的概念和术语。

Fire OS 辅助功能对象和事件概述

本节介绍了在应用中实现辅助功能时将会用到的对象和事件的术语及其定义。

AccessibilityEvent

AccessibilityEvent 是应用向辅助技术发送的消息,指示 UI 中发生了某些事情。可触发辅助功能事件的 UI 更改示例包括焦点更改、窗口出现或消失,或者屏幕上的对象更改位置。

请参阅介绍 AccessibilityEvents 的安卓文档。

AccessibilityNodeInfo

AccessibilityNodeInfo 是与屏幕上的组件相关的辅助功能信息的快照,主要提供应用和辅助技术之间的单向通信。辅助技术通过辅助功能操作与应用进行的通信也非常有限。

应用创建并返回 AccessibilityNodeInfo 后,辅助技术和辅助功能框架将不会看到对该节点的任何后续更改,因此,此时您可以放弃该节点。如果节点表示的基础对象发生更改,则发送一个适当的辅助功能事件,指示该更改,在下次调用 createAccessibilityNodeInfoonInitializeAccessibilityNodeInfo 返回的节点中反映对象的更新特征。

在应用中,在服务器端,使用安卓视图和虚拟后代编号的组合引用节点。如果节点表示视图本身,则虚拟后代编号为 -1 (AccessibilityNodeProvider.HOST_VIEW_ID)

应用可以在该对象的 getExtras 捆绑包中添加有关 AccessibilityNodeInfo 对象的描述性信息,VoiceView 可以通过调用 AccessibilityNodeInfo.getExtras() 来读取该信息。

请参阅介绍 AccessibilityNodeInfo 的安卓文档。

AccessibilityNodeProvider

AccessibilityNodeProvider 是一个接口,用于为视图或视图的实际可访问后代创建 AccessibilityNodeInfo

请参阅介绍 AccessibilityNodeProvider 的安卓文档。

AccessibilityDelegate

AccessibilityDelegate 是一个可以初始化辅助功能事件、视图节点或实际可访问后代的接口。使用 AccessibilityDelegates 从一个视图中的信息代理或扩充另一个视图中的辅助功能信息。例如,父列表可以为列表项提供辅助功能信息。

请参阅介绍 AccessibilityDelegate 的安卓文档。

辅助功能事件的路径

本节讨论标准视图和自定义视图的辅助功能事件路径。

标准视图

构成 Fire OS 应用用户界面的可视元素称为“视图”。例如,考虑一个简单的应用,它具有单个文本元素,即一个包含文本“hello world”的 TextView。在此示例中,TextViewRelativeLayout 的子级。RelativeLayoutViewRootImpl 的子级,该类始终是应用视图层次结构的根目录。由于 TextView 是一个标准的安贞视图,因此 TextView 的默认行为是在 VoiceView 运行时发送适当的辅助功能事件。

以下过程描述了在此简单应用中创建的辅助功能事件的路径: 

  1. 应用的代码在应用打开几秒钟后调用 textView.setText("new text")
  2. TextView 创建一个 TYPE_WINDOW_CONTENT_CHANGED AccessibilityEvent 并请求其父级 RelativeLayout 发送该事件。
  3. 然后,RelativeLayout 将事件向上传递给其父级 ViewRootImpl,并请求它将事件发送到框架。
  4. ViewRootimpl 通过调用 AccessibilityManagersendAccessibilityEvent() 将事件发送到辅助功能框架。
  5. AccessibilityManager 将事件传递给 AccessibilityManagerService,后者将事件从辅助功能框架传递到 VoiceView 中。
  6. 当 VoiceView 处理 TYPE_WINDOW_CONTENT_CHANGED AccessibilityEvent 时,它会调用事件对象的 getSource() 方法。
  7. 这将触发辅助功能框架来调用 TextView 的 createAccessibilityNodeInfo() 方法,该方法返回一个包含文本“new text”的 AccessibilityNodeInfo 对象。
  8. 辅助功能框架随后将 AccessibilityNodeInfo 对象传递到 VoiceView。
  9. 最后,VoiceView 意识到 TextView从“hello world”变为“new text”,如果客户使用线性导航来聆听 TextView 的文本,VoiceView 将会正确地说出“new text”。

自定义视图

如果您的应用使用自定义视图而不是标准视图,则必须坚持使用这种模式将小部件的状态告知 VoiceView。执行此操作时,请勿尝试将 AccessibilityNodeInfo 对象发送到 VoiceView,或更新应用中 AccessibilityNodeInfo 的本地副本;这些方法将不起作用。

请记住,当您更改自定义小部件的状态时:

应该

  • 通过对自定义视图的父项调用 requestSendAccessibilityEvent() 来发送 AccessibilityEvent
  • 确保自定义视图的 createAccessibilityNodeInfo() 函数中指向的变量包含更新的值。VoiceView 收到您的 AccessibilityEvent 时调用 createAccessibilityNodeInfo()

切忌

  • 尝试将 AccessibilityNodeInfo 发送到 VoiceView。
  • createAccessibilityNodeInfo() 函数之外保留对 AccessibilityNodeInfo 对象的引用,然后更新这些对象。VoiceView 无法引用这些对象,并且永远不会看到您对这些对象的更新。

在安卓文档中,请务必查看一个演示正确使用 AccessibilityDelegateAccessibilityNodeProvider 类的代码示例,其中实现了 createAccessibilityNodeInfo() 函数。

设置视图的重要性

要确保正确处理辅助功能事件,请确保为每个安卓视图设置辅助功能的重要性。 

在 XML 布局中使用 android:importantForAccessibility 属性或以编程方式使用 View.setImportantForAccessibility 方法,设置视图状态对辅助功能的重要性。您可以将重要性设置为 yes, no, no_hide_descendantsauto(默认)。未标记为重要的视图没有相应的辅助功能节点,此外,框架会删除它们发送的任何辅助功能事件。

如果您的视图正在发送适当的辅助功能事件,但 VoiceView 似乎没有正确响应,请验证您的视图是否标记为对辅助功能非常重要。

管理 AccessibilityNodeInfo 对象

Fire OS 和安卓辅助功能的一个重要方面是 AccessibilityNodeInfo 对象的管理。当在应用进程中运行的安卓辅助功能框架收到针对特定节点的请求时,框架首先检查节点是否在其缓存中:

  • 如果缓存中存在节点,则返回该节点,并且不会调用应用以创建节点。因此,每当有关组件的辅助功能信息发生变化时,您的应用都必须努力通知框架和辅助技术。否则,框架会将过时的信息返回给辅助技术。
  • 要指示节点已更改且不再有效,请发送类型为 AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED 的辅助功能事件。
  • 如果节点尚未在缓存中,则可以创建节点,具体取决于它的请求方式。辅助技术的几个可能操作可以触发 AccessibilityNodeInfo 对象的创建:
    • 接收辅助功能事件并请求其源。
    • 请求活动窗口的根节点。
    • 请求特定节点的父节点或子节点。

实现实际可访问的后代

本节讨论如何实现实际可访问的后代视图。

创建实际可访问的后代视图

AccessibilityDelegateAccessibilityNodeProvider 都可以为未由支持视图表示的屏幕组件提供辅助功能。此类组件的一个示例是 AOSP 屏幕键盘,其键在画布上绘制。请注意,在实现虚拟节点树时,安卓提供的 ExploreByTouchHelper 支持库可能无法按预期工作。

应用通过托管节点的视图和虚拟视图 ID 引用 AccessibilityNodeInfo 对象。虚拟视图 ID -1 (AccessibilityNodeProvider.HOST_VIEW_ID) 引用主机视图本身。创建节点时,您可以使用 AccessibilityNodeInfo.addChild() 方法添加虚拟子节点,并指定虚拟子节点的主机视图和虚拟视图 ID。同样,在创建子节点时,您可以通过在 AccessibilityNodeInfo.setParent() 调用中指定主机视图和父虚拟视图 ID 来设置虚拟父节点。

管理实际可访问的后代视图

最初创建虚拟视图时,它们仅由其 ID 引用,并且没有关联的辅助功能信息(文本、内容描述等)。当辅助功能框架请求您的应用创建相应的节点时,请将相应的辅助功能信息输入到 AccessibilityNodeInfo 中。因此,请确保您的应用跟踪哪个虚拟视图 ID 表示自定义小部件的哪个部分。

添加子节点或父节点的 ID,框架稍后请求您的应用实际创建这些节点。不要简单地将子节点添加到容器节点。

Fire OS 辅助功能最佳实践

要确保具有辅助功能的应用获得最佳用户体验,请遵循以下指南:

  • AccessibilityNodeInfo 文本AccessibilityNodeInfo 的文本应只返回对象的屏幕文本。
  • 屏幕上项目的标签: 屏幕上的所有重要项目都应具有标签。确保使用 VoiceView 进行测试时,触摸屏幕上的所有项目,并且听到正确的描述。如果缺少描述,请将相应的文本或内容描述添加到项目的 AccessibilityNodeInfo 中。
  • 内容描述: 对没有屏幕文本的项目使用内容描述(例如,图像的替代文本),或者扩充屏幕文本以向用户提供附加上下文。但是,避免在内容描述中放置过多的内容,以避免让用户无所适从。
  • 辅助功能事件用法: 避免使用 AccessibilityEvent.TYPE_ANNOUNCEMENT 事件类型来传达屏幕上的活动。最好使用辅助功能事件和对 AccessibilityNodeInfo 的相应更改的组合来传达有关屏幕更改的信息。