Accessibility(辅助功能、易用性服务)

概述

有许多的残障安卓用户,这就要求安卓设备有不同的界面与之交互。这包括视觉上,身体上或者与年龄相关的残疾而完全阻止他们看到或使用触摸屏。
安卓提供了辅助功能和服务为帮助这些用户更加简单的使用设备,包括语音合成,触觉反馈,轨迹球和方向键导航来增强他们的体验。安卓开发者可以利用这些服务让应用程序更加的易用,当然也可以构建自己的辅助功能。

让应用程序易于使用

当残障用户激活设备上的辅助功能和服务时,构建在安卓上的应用程序变得易于使用。默认的,这些服务让你的应用程序变得更加的易于使用。然而,你应该采取进一步措施来优化应用程序的易用性,确保所有用户的体验。
确保你的应用对所有的用户都方便使用是相对容易的,尤其是当你使用框架提供的界面组件时。如果你仅仅在应用中使用标准组件,这里有几个步骤以确保应用的易用:
  1. 通过使用android:contentDescription 属性标注你的ImageButtonImageViewEditTextCheckBox 和其他UI组件。
  2. 通过一个直接控制器让你所有的用户界面元素易用。例如轨迹球或方向键。
  3. 测试您的应用程序通过将易用性服务反馈和探索触摸,试图使你的应用只使用一个定向控制器。
开发者通过继承View创建的自定义控件需要一些额外的职责,那就是确保该控件对所有用户都是易用的。将会在之后提到如何增加自定义控件的可用性。

标记用户界面元素

许多用户界面控件依赖视觉提示告知用户他们的意思,如,一个笔记应用或许会使用一个带加号图片的按钮来表明用户可以添加一个新的笔记。又如,一个文本编辑组件或许有一个标签在附近用来标识目的。 当视力受损的用户访问您的应用程序,这些视觉线索通常是无用的。
提供关于界面控件的文本信息(作为视觉线索的替代 ),使用 android:contentDescription 属性。在该属性中指定的文本不会显示在屏幕上, 但如果用户启用了易用性服务提供的声音提示,这个属性的描述便会大声的朗读给用户。
为你应用中的每一个 ImageButton ImageView EditText CheckBox   和其他输入控件 设置 android:contentDescription   ,当 用户无法看到它时 可能需要额外的信息,
例如,下面的图片按钮设置了内容描述为add_note的字符串资源。
   
   
<ImageButton
android:id=”@+id/add_note_button”
android:src=”@drawable/add_note”
android:contentDescription=”@string/add_note”/>
通过包含该描述, 当用户移动焦点按钮或将鼠标悬停于该控件上时, 基于语音的可访问性服务可以宣读“添加笔记”。

启用焦点导航

焦点疾导航允许用户 使用定向控制器次序穿过 界面控件。定向控制器可以是物理的,例如一个可点击的轨迹球,方向键或者十字键,tab键导航 附带一个键盘和一个软件应用程序,,例如,快捷按键( Eyes-Free Keyboard )提供了一个在屏幕上的直接控制器。
定向控制器 对于许多用户来说 是一种主要的导航工具。 验证所有的用户界面(UI)控件在您的应用程序都可以访问,当 不使用触摸屏时。 单击中心按钮(或OK按钮)定向控制器和触摸屏上的触摸控制的效果一样。详情请看之后的 #测试焦点导航

启用视图的焦点

一个用户界面元素可以使用定向控制当android:focusable属性设置为true时。此设置允许用户关注的元素使用定向控制,然后与之交互。安卓框架提供的用户界面程序在缺省的情况下都是可聚焦的,并且通过改变控件的外观直观表明获得了焦点。
Android提供了一些api,让你控制用户界面控件是否可聚焦甚至要求控制给予焦点:
当使用默认设置成不可定焦的视图,可以在xml布局文件中通过设置属性 android:focusable 为true或者使用 setFocusable()   方法让其可聚焦。

控制焦点顺序

当用户导航在任何方向使用定向控制时,焦点从一个用户界面(View)到达另一个,顺序为焦点的排序。焦点运动的顺序是根据一个算法: 在一个给定的方向 找到最近的相邻项。 在极少数情况下,默认的算法可能在你的UI中的顺序不匹配。此时,你可以提供显式重写,在布局文件中使用以下XML排序属性:
android:nextFocusDown
Defines the next view to receive focus when the user navigates down. android:nextFocusLeft
Defines the next view to receive focus when the user navigates left.
android:nextFocusRight
Defines the next view to receive focus when the user navigates right.
android:nextFocusUp
Defines the next view to receive focus when the user navigates up

下面这个示例展示了它的使用方法:
   
   
<LinearLayout android:orientation="horizontal"
... >
<EditText android:id="@+id/edit"
android:nextFocusDown=”@+id/text”
... />
<TextView android:id="@+id/text"
android:focusable=”true”
android:text="Hello, I am a focusable TextView"
android:nextFocusUp=”@id/edit”
... />
</LinearLayout>
当修改焦点顺序时,确保导航工作按照预期的工作和反向工作(回到你来的地方)。
注:可以在运行时修改界面焦点顺序,使用如下类似的方法 setNextFocusDownId()  and  setNextFocusRightId() .

构建自定义的可访问性视图

如果你的view需要使用自定义的view控件,你必须做一些额外的工作确保你的自定义控件变得易用( accessible ).下面是一些主要的任务来确保你的view的 accessibility  :

处理直接控制器点击

大多数设备上,使用直接控制器点击一个view时会立即发送一个 KEYCODE_DPAD_CENTER  的   KeyEvent  所有的安卓标准view已经适当的处理了这个事件。当构造自定义View控件时,确保这个事件也能得到像在触摸屏上触摸view一样的效果。
你的自定义控件也应该像处理   KEYCODE_DPAD_CENTER .一样处理 KEYCODE_ENTER  。这个方法使得用户使用全键盘设备时更加简单。

实现Accessibility API的方法

可访问性事件作为消息在你的应用中与视觉界面组件进行交互。这些信息由 Accessibility Services 处理, Accessibility Services ,使用这些事件中的信息产生补充反馈并且当启用了 accessibility services时 提示用户。在 Android 4.0 (API Level 14)  或更高版本中,生成 accessibility events被扩展了许多详细的信息,除了  在   Android 1.6 (API Level 4)中引入的 AccessibilityEventSource  接口。扩展的 accessibility  方法是View类和   View.AccessibilityDelegate  类 的一部分。方法如下:
sendAccessibilityEvent()
(API Level 4)当用户在view上有动作时被调用。该事件被分类为用户操作类型(如 TYPE_VIEW_CLICKED.)。通常你无需实现这个方法除非你在创建一个自定义view.
sendAccessibilityEventUnchecked()
(API Level 4)当代码中需要检查直接控制器的accessibility 是否在设备上启动( AccessibilityManager.isEnabled())时调用。如果你实现类这个方法,你必须假设调用方法以及检查了accessibility 是可用的并且返回结果为true。通常不在自定义view中实现该方法。
dispatchPopulateAccessibilityEvent()
(API Level 4)当你的自定义view产生一个accessibility event时由系统调用这个方法,它的默认实现是为view调用了 onPopulateAccessibilityEvent() 然后为每个子vew调用  dispatchPopulateAccessibilityEvent()为了支持在安卓4.0之前的版本的accessibility services,你必须覆盖该方法并且使用 getText() 为你的自定义view填充描述性文字。
onPopulateAccessibilityEvent()
(API Level 14)该方法为你的view设置 AccessibilityEvent的输出文字。该方法也经常在子view产生一个accessibility event.时被调用。
:在文本中修改附加属性这种方法可能覆盖其他方法的属性设置。因此,当你使用这个方法修改accessibility event的属性时,你应该仅限于更改文本的内容,使用 onInitializeAccessibilityEvent()方法去更改其它event的属性。
:如果你实现这个事件调用了完全覆盖输出文本并且不希望你的其他部分修改其内容,就不需要去调用父类的该方法。
onInitializeAccessibilityEvent()
(API Level 14)系统调用该方法,在获得了除文本内容之外的额外消息时。如果你的自定义布局提供一个交互式控制超过一个简单的textview或button,你应该覆盖这个方法并且在该方法中为你的view附加额外信息,例如密码文本类型,复选框类型或提供给用户交互的状态或反馈。一旦你覆盖了这个方法,你必须调用它的父类实现方法,然后仅仅修改属性而不设置属性。
onInitializeAccessibilityNodeInfo()
(API Level 14) 这个方法提供了关于view的状态信息的accessibility services。默认view实现了一组标准view的设置,但是如果你的自定义视图提供交互式控制超越简单的TextView或按钮,你应当覆盖这个方法并且设置为你的view设置额外的信息,在该方法中通过  AccessibilityNodeInfo对象进行处理。
onRequestSendAccessibilityEvent()
(API Level 14)当你的子view生成了一个 AccessibilityEvent. 时调用。允许这个父view为这个accessibility event添加额外信息。如果你的自定义view有子view && 父view为accessibility event 提供上下文信息,实现这个方法,会对accessibility services.十分有帮助。
为你的自定义view支持这些 accessibility  方法, 你应该采取下列方法之一:
  • 如果你的应用目标是Android 4.0 (API level 14)或更高,直接在你的自定义view类中覆盖并重写这些方法。
  • 如果你的自定义布局需要兼容 Android 1.6 (API Level 4)或更早版本,在你的工程中加入Android Support Library,第5版本或更高版本。然后在你的自定义view中调用ViewCompat.setAccessibilityDelegate() 方法来实现之前的accessibility 方法。
不论什么情况,你都应该为你的自定义view实现如下方法:
有关实现这些方法的更详细信息,请看 #填充accessibility事件

发送accessibility事件

取决于你自定义view的细节,或许需要 在不同时机 发送不同的 AccessibilityEvent  对象,或者事件不是由默认实现处理的。View 类提供了一个默认实现这些事件类型:
悬停事件是通过触摸功能探测的,使用这些事件作为触发器为ui元素提供听觉提示。
总之,当你的自定义view内容改变时应该发送 AccessibilityEvent。例如,如果你实现一个允许用户通过左右箭头选择数字的自定义滚动条,当滑动值改变时,你的自定义控件应该发出 TYPE_VIEW_TEXT_CHANGED  事件。下面的代码示例演示了在 sendAccessibilityEvent()  中 如何报告这个事件
    
    
@Override
public boolean onKeyUp (int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
mCurrentValue--;
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
return true;
}
...
}

填充accessibility事件

每一个   AccessibilityEvent has  都有一组必要属性用来描述view当前状态。这些属性包括例如view的类名,内容描述和是否被选中。具体的属性要求每一个事件类型在 AccessibilityEvent  参考文档中都有描述。View类实现并提供了这些属性的默认值。许多值,包括类名和事件的时间戳,都自动的提供了。如果你创建自定义view,你必须提供一些关于该view的内容和特征信息。这些信息可能像标签按钮,但是如果想加入事件也可以包含额外的状态信息。
对在自定义布局中为 accessibility services 提供信息的最低要求是实现 dispatchPopulateAccessibilityEvent() .这个方法在系统请求 AccessibilityEvent  消息时调用,同时确保你的vew和 accessibility services 兼容   Android 1.6 (API Level 4)或更高版本。下面的示例代码演示了这个函数的基本实现
    
    
@Override
public void dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
super.dispatchPopulateAccessibilityEvent(event);
// Call the super implementation to populate its text to the event, which
// calls onPopulateAccessibilityEvent() on API Level 14 and up.
 
// In case this is running on a API revision earlier that 14, check
// the text content of the event and add an appropriate text
// description for this custom view:
CharSequence text = getText();
if (!TextUtils.isEmpty(text)) {
event.getText().add(text);
}
}
  Android 4.0 (API Level 14)  和更高版本,   onPopulateAccessibilityEvent()  和 onInitializeAccessibilityEvent() methods  方法是推荐方式,用以填充或修改   AccessibilityEvent .中的信息。使用   onPopulateAccessibilityEvent()  方法 专门添加或修改的文字内容,该文字内容会变成声音提示的可访问性服务。使用   onInitializeAccessibilityEvent()  方法 填充额外的关于事件的信息,如视图的选择状态。
另外,你还应实现   onInitializeAccessibilityNodeInfo()  方法。该方法中的 AccessibilityNodeInfo 对象被 accessibility services 用来调查view的层次结构,在接受该事件后生成一个事件,为了获得更加详细的文本信息并且给用户提供适当的反馈。
下面的示例代码展示了如何覆盖这三方法
,通过使用 ViewCompat.setAccessibilityDelegate() . 注意,这个示例代码需要添加  Android  Support Library  版本为5或更高到你的工程中。
    
    
ViewCompat.setAccessibilityDelegate(new AccessibilityDelegateCompat() {
@Override
public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
super.onPopulateAccessibilityEvent(host, event);
// We call the super implementation to populate its text for the
// event. Then we add our text not present in a super class.
// Very often you only need to add the text for the custom view.
CharSequence text = getText();
if (!TextUtils.isEmpty(text)) {
event.getText().add(text);
}
}
@Override
public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(host, event);
// We call the super implementation to let super classes
// set appropriate event properties. Then we add the new property
// (checked) which is not supported by a super class.
event.setChecked(isChecked());
}
@Override
public void onInitializeAccessibilityNodeInfo(View host,
AccessibilityNodeInfoCompat info) {
super.onInitializeAccessibilityNodeInfo(host, info);
// We call the super implementation to let super classes set
// appropriate info properties. Then we add our properties
// (checkable and checked) which are not supported by a super class.
info.setCheckable(true);
info.setChecked(isChecked());
// Quite often you only need to add the text for the custom view.
CharSequence text = getText();
if (!TextUtils.isEmpty(text)) {
info.setText(text);
}
}
}
应用目标版本为4.0或更高时,这些方法可以在你的自定义view类中直接被定义。查看别的与这个差不多的示例,在 Android  Support Library  (revision 5 or higher) sample  AccessibilityDelegateSupportActivity  ( <sdk>/extras/android/support/v4/samples/Support4Demos/ ).
注: on  你必须在4.0之前的版本中可以找到自定义view的覆盖可用性的信息,那就是使用 dispatchPopulateAccessibilityEvent()方法来填充 AccessibilityEvents。随着4.0版本的到来,更推荐使用 onPopulateAccessibilityEvent() onInitializeAccessibilityEvent()  方法。

测试辅助功能(Accessibility)

为你的应用进行辅助功能的测试是确保用户体验十分重要的一部分。你可以测试声音反馈的可用性和直接控制器的导航性这些易用性最重要的部分。

测试声音反馈

在开启易用性服务后,可以模拟大多数用户的经验习惯,在屏幕的各个地方说话。 Explore by Touch 易用性服务,该服务在4.0及其之后版本的设备上可以使用。   TalkBack   易用性服务,在预装了   Eyes-Free Project 上的安卓设备上可以使用。

在安卓4.0之前的版本启用   TalkBack  :
  1. 启动设置(Settings)
  2. 进入到辅助功能(Accessibility) 类别并且选择它
  3. 选择Accessibility 并启用它
  4. 选择TalkBack 并启用它
:如果 TalkBack  服务不可用,你可以在Google Play免费下载并安装。

在安卓4,0之后启用 Explore by Touch
  1. 启动Settings 
  2. 进入到Accessibility 类别并选择它
  3. 选择TalkBack 并启用它
  4. 返回Accessibility 并选择Explore by Touch ,启用它
注:你必须先打开 TalkBack  ,否则这个设置不会起作用。

测试焦点导航

作为易用性测试的一部分,你可以在应用中通过使用焦点来测试导航性,即使你的测试设备上没有直接控制器。 Android Emulator提供了一个模拟控制器来方便这项测试。你也可以使用基于软件的直接控制器,例如 Eyes-Free Keyboard 用来模拟方向键。

构建Accessibility Services

一个 accessibility service是提供给残疾用户或者设备暂时无法完全交互的人,用以增强应用中用户界面的服务。例如用户正在喝酒、照顾小孩或者参加一个十分吵闹的聚会时或许需要额外的或替代反馈接口。
安卓提供了标准的 accessibility service,包括 TalkBack,当然开发者也可以创建并分发他们自己的service。这篇文章将会展示你构建 accessibility service的 基础方法。
在安卓1.6(API Leve 4)中可以 署和构建 accessibility service部 ,在 Android 4.0 (API Level 14)进行了重大的改进。随着安卓4.0的发布, Android Support Library  提供的相关方法也进行了更新。开发者的目标是为了 广泛兼容的易用性服务,在安卓4.0中鼓励使用   Support Library和开发先进的交互特性。

清单(Manifest)中进行声明和权限

应用程序提供的易用性服务必须在它的 manifests进行声明,目的是为了安卓系统将其作为易用性服务来对待。

Accessibility service的声明

为了将其作为易用性服务对待,你的应用必须在manifest文件的 application下包含 service标签(而不是 activity标签)。另外,除了service标签,必须包含一个 accessibility service信息过滤器( intent filter ),如下所示:
    
    
<application>
<service android:name=".MyAccessibilityService"
android:label="@string/accessibility_service_label">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
</service>
</application>
在安卓1.6或更高版本之后必须要求有该声明。

accessibility service的配置

accessibility service必须提供一个配置用来指定accessibility event的类型,用来在该service中处理和增加信息。 accessibility service的配置包含在 AccessibilityServiceInfo  类中。在运行时使用该类的一个实例和 setServiceInfo()  方法构造和配置你的service。
从安卓4.0开始,你可以在你的manifest中包含 <meta-data>  标签作为配置文件的参考,该文件允许你为你的 accessibility service进行全方位的配置,如下所示:
    
    
<service android:name=".MyAccessibilityService">
...
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/accessibility_service_config" />
</service>
这个meta-data 标签是创建在资源文件夹下的xml文件 ( <project_dir>/res/xml/accessibility_service_config.xml )。下面展示了该配置文件的例子:
    
    
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/accessibility_service_description"
android:packageNames="com.example.android.apis"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFlags="flagDefault"
android:accessibilityFeedbackType="feedbackSpoken"
android:notificationTimeout="100"
android:canRetrieveWindowContent="true"
android:settingsActivity="com.example.android.accessibility.ServiceSettingsActivity"
/>
accessibility service配置中一个最重要的参数是 允许您指定您的服务可以处理什么类型的 accessibility events   。当与其他   accessibility services合作时,确保该消息的唯一性,并且允许开发者使用特别的应用来处理这一特别的事件。事件过滤可以遵循如下标准:
  • 包名-独一无二的包名可以标识出你的service 希望处理谁的 accessibility event。如果这个参数受限,你的 accessibility services被认为是在任何应用中都可用的。这部分可以在 accessibility services设置文件中使用 android:packageNames 属性中用逗号分隔来进行设置。或者使用AccessibilityServiceInfo.packageNames 下的成员设置。
  • 事件类型-你的service 处理的accessibility events 是独一无二的。这部分可以在accessibility 配置文件中通过android:accessibilityEventTypes attribute 属性用逗号分隔进行设置,或者使用AccessibilityServiceInfo.eventTypes 成员进行设置。
更多关于该配置文件的属性值信息请查看【延伸阅读】
更多关于何种配置设置能在运行时动态设置,请看 AccessibilityServiceInfo 参考文档

accessibility service 的方法

一个应用提供了accessibility service 必须继承 AccessibilityService  类并且覆盖该类的一些方法。这些方法给出的顺序是安卓系统调用的顺序。从service 开始启动 ( onServiceConnected() ) ,正在运行 ( onAccessibilityEvent() onInterrupt() ) ,到结束  ( onUnbind() ).。
  • onServiceConnected() - (可选的)当成功连接了你的accessibility service 时被系统调用。在这个方法中为你的service 设置一些一次性的设置工作,包括连接用户反馈系统服务(user feedback system services),例如音频管理器或设备震动器。如果想在运行时配置你的service 或者一次性调整适应,调用 setServiceInfo().方法是一个合适的开始位置。
  • onAccessibilityEvent() - (必须)当发现一个符合你过滤规则的accessibility event 时被系统调用。例如,用户点击了一个按钮或将焦点放到它上面,你的辅助服务将提供反馈信息。当这样的情况发生时,系统就会调用与accessibility event 相关的你的服务。这时你可以处理并提供反馈给用户。该方法将会在你service 的生命周期中调用多次。
  • onInterrupt() - (必须)当系统要打断你提供的反馈服务时被调用。通常以响应用户采取的行动,例如移动焦点到不同的界面。该方法将会在你service 的生命周期中调用多次。
  • onUnbind() -(可选)当系统将要关闭accessibility service 时调用。使用该方法进行设置一次性的关闭程序,包括还原用户反馈系统服务,如音频管理和设备震动器。
这些回调方法为你的accessibility service 提供了基本的结构。它 取决于你如何处理由安卓系统提供的数据,这些数据在   AccessibilityEvent 表格对象和给用户的反馈信息。

获取事件详情

安卓系统提供 通过accessibility event 对象获取用户界面交互信息 给accessibility services 。在安卓4.0之前,这些可得到的信息在一个accessibility event 中,同时提供大量的 关于用户如何选择和控制界面 的细节信息。通常是上下文信息。在许多情况下,这些被忽略的上下文信息或许会变得对于理解 用户选择的意义 十分重要。
一个典型的例子,一个接口在至关重要的 日历或日计划上。如果用户在一个周一到周五的选择框中 选择了的4:00 PM,并且accessibility 服务报时“4 PM ”,但是未能表明这是周一还是周五,这个月或者这一天,这并非理想的使用反馈。在这个实例中,用户界面提供的上下文对那些或许想安排一个会议的用户来说是至关重要的。
安卓4.0显著的扩展了大量的信息。一个accessibility service 通过一个基于view的层级结构来自定义的accessible events  来获取关于用户界面的信息。一个view的层次结构是一个包含用户界面组件(父view)和可能包含的组件(子view)的集合。如此一来,安卓系统能够为accessibility events 提供更加丰富的细节,允许accessibility services 向用户提供更有用的反馈。
一个accessibility service 通过在service中的 onAccessibilityEvent()  回调函数中的 AccessibilityEvent 获取关于用户界面的信息。该对象提供了事件的细节,包括对象的类型,它的描述性语言和其它细节。始于安卓4.0(在早期版本可以通过使用Support Library 中的 AccessibilityEventCompat对象 ),通过调用如下方法,你可以获得事件的具体信息:
注意:在你的accessibility service 中通过   AccessibilityEvent 调查整个view层次结构有潜在的暴露用户信息的风险。因为这个原因,你的service 必须通过accessibility service 设置文件  请求这一级别的访问权限,通过包含 canRetrieveWindowContent  属性并设置为 true . 如果你不这么做,在调用   getSource() 会失败。

示例代码

本地文件是如下路径:<sdk>/samples/<platform>/ApiDemos/src/com/example/android/apis/accessibility
  • ClockBackService -这个服务是基于AccessibilityService的原始实现和可以用来作为基础开发基本无障碍服务兼容安卓1.6(API级别4)和更高。
  • TaskBackService - 这个服务是基于增强的易访问性API在Android 4.0中引入的(API级别14)。不过,您可以使用Android Support Libary 替代类中引入后的API(如AccessibilityRecord AccessibilityNodeInfo)等价的支持包类(如AccessibilityRecordCompat AccessibilityNodeInfoCompat)使这个例子在API版本Android 1.6(API级别4)或更低版本使用。


延伸阅读

有关于安卓accessibility service 设置文件中可使用的的xml属性:
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值