构建无障碍服务

An accessibility service is an application that provides user interface enhancements to assist users with disabilities, or who may temporarily be unable to fully interact with a device. For example, users who are driving, taking care of a young child or attending a very loud party might need additional or alternative interface feedback.

无障碍服务是一个为残疾人或可能暂时无法与设备完全互动的人提供用户界面扩展功能的应用程序。例如,在开车、照顾孩子或参加一个非常喧闹的宴会时,用户可能需要另外的交互反馈作为补充或替代。

Android provides standard accessibility services, including TalkBack, and developers can create and distribute their own services. This document explains the basics of building an accessibility service.

Android提供了标准的无障碍服务,包括TalkBack,开发人员可以创建和发布自己的服务。 本文档介绍了构建无障碍服务的基本知识。

The ability for you to build and deploy accessibility services was introduced with Android 1.6 (API Level 4) and received significant improvements with Android 4.0 (API Level 14). The Android Support Library was also updated with the release of Android 4.0 to provide support for these enhanced accessibility features back to Android 1.6. Developers aiming for widely compatible accessibility services are encouraged to use the Support Library and develop for the more advanced accessibility features introduced in Android 4.0.

构建和部署无障碍服务的能力在Android 1.6(API等级4)被推出,并在Android 4.0(API等级14)明显改善其功能。Android支持库也被更新,Android 4.0发布的支持库可以使得这些无障碍特性也能支持android 1.6。鼓励那些致力于实现广泛可兼容的无障碍服务开发者们使用支持库,并且在Android4.0版本中开发更多先进的无障碍特性。

Manifests声明和权限

Applications that provide accessibility services must include specific declarations in their application manifests to be treated as an accessibility service by the Android system. This section explains the required and optional settings for accessibility services.

提供无障碍服务的应用,必须在应用的声明(manifests)文件中明确声明,以便android系统把此应用程序作为无障碍服务处理。本节介绍无障碍服务的必需和可选设置。

无障碍服务声明

In order to be treated as an accessibility service, you must include a service element (rather than the activity element) within the application element in your manifest. In addition, within the service element, you must also include an accessibility service intent filter. For compatiblity with Android 4.1 and higher, the manifest must also request the BIND_ACCESSIBILITY_SERVICE permission as shown in the following sample:

为了能被看作一个无障碍服务,必须在声明文件中的应用程序(application)元素中包含服务(service)元素(而不是活动(activity)元素)。此外,在服务(service)元素内,还必须包括无障碍服务的目标过滤器。为了兼容Android 4.1及更高版本的系统,声明文件中必须请求BIND_ACCESSIBILITY_SERVICE的权限,如下例所示:

<manifest>
  ...
  <uses-permission ... />
  ...
  <application>
    ...
    <service android:name=".MyAccessibilityService"
        android:label="@string/accessibility_service_label"
        android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
      <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService" />
      </intent-filter>
    </service>
    <uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />
  </application>
</manifest>

These declarations are required for all accessibility services deployed on Android 1.6 (API Level 4) or higher.

在Android 1.6(API等级4)和更高版本的系统中,所有无障碍服务都需要部署这些声明。

无障碍服务配置

Accessibility services must also provide a configuration which specifies the types of accessibility events that the service handles and additional information about the service. The configuration of an accessibility service is contained in the AccessibilityServiceInfo class. Your service can build and set a configuration using an instance of this class and setServiceInfo() at runtime. However, not all configuration options are available using this method.

无障碍服务还必须提供一个配置,该配置指定了无障碍服务处理的无障碍事件类型和有关无障碍服务的附加信息。无障碍服务的配置被包含在AccessibilityServiceInfo类中。无障碍服务可以使用该类的实例创建一个配置,并在运行时使用setServiceInfo()设置此配置。但是,使用该方法并不能配置所有的配置项。

Beginning with Android 4.0, you can include a <meta-data> element in your manifest with a reference to a configuration file, which allows you to set the full range of options for your accessibility service, as shown in the following example:

从Android 4.0开始,可以在声明文件中包含一个<meta-data>元素,该元素指向一个配置文件。该配置文件允许开发者设置无障碍服务的所有内容,具体如下例所示:

<service android:name=".MyAccessibilityService">
  ...
  <meta-data
    android:name="android.accessibilityservice"
    android:resource="@xml/accessibility_service_config" />
</service>

This meta-data element refers to an XML file that you create in your application’s resource directory (<project_dir>/res/xml/accessibility_service_config.xml). The following code shows example contents for the service configuration file:

该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"
/>

For more information about the XML attributes which can be used in the accessibility service configuration file, follow these links to the reference documentation:

无障碍服务配置文件使用的XML属性,点击以下链接查看更多信息:

For more information about which configuration settings can be dynamically set at runtime, see the AccessibilityServiceInfo reference documentation.

哪些配置设置可以在运行时动态地设置的详细信息,请参阅AccessibilityServiceInfo参考文档。

注册无障碍事件

One of the most important functions of the accessibility service configuration parameters is to allow you to specify what types of accessibility events your service can handle. Being able to specify this information enables accessibility services to cooperate with each other, and allows you as a developer the flexibility to handle only specific events types from specific applications. The event filtering can include the following criteria:

无障碍服务配置参数最重要的功能之一是允许开发者指定无障碍服务能处理的无障碍事件类型。成功指定该信息使无障碍服务间能相互合作,并允许开发者灵活地处理特定应用的特定事件类型。事件过滤可以包含以下规则:

  • Package Names - Specify the package names of applications whose accessibility events you want your service to handle. If this parameter is omitted, your accessibility service is considered available to service accessibility events for any application. This parameter can be set in the accessibility service configuration files with the android:packageNames attribute as a comma-separated list, or set using the AccessibilityServiceInfo.packageNames member.
    包名(PackageNames): - 指定想要无障碍服务处理的无障碍事件的应用程序包名。如果省略该参数,无障碍服务将被视为服务于任何应用程序的无障碍事件。在无障碍服务配置文件中,该参数可使用android:packageNames属性被设置为一个逗号分隔的列表,或使用AccessibilityServiceInfo.packageNames成员设置。
  • Event Types - Specify the types of accessibility events you want your service to handle. This parameter can be set in the accessibility service configuration files with the android:accessibilityEventTypes attribute as a list separated by the | character (for example accessibilityEventTypes="typeViewClicked|typeViewFocused"), or set using the AccessibilityServiceInfo.eventTypes member.
    事件类型(Event Types) - 指定开发者想要无障碍服务处理的无障碍事件的类型。在无障碍服务配置文件中,该参数可使用android:accessibilityEventTypes属性设置为由“ | ”分隔的列表(例如accessibilityEventTypes="typeViewClicked|typeViewFocused"),或者使用AccessibilityServiceInfo.eventTypes成员设置。

When setting up your accessibility service, carefully consider what events your service is able to handle and only register for those events. Since users can activate more than one accessibility services at a time, your service must not consume events that it is not able to handle. Remember that other services may handle those events in order to improve a user's experience.

当创建无障碍服务时,开发者需要全面考虑无障碍服务能处理的无障碍事件,并只注册这些事件。因为用户可能同时激活多个无障碍服务,开发者创建的服务不能浪费在该服务不能处理的事件上。记住,其他的服务也可能会为了提供用户体验来处理这些事件。

Note: The Android framework dispatches accessibility events to more than one accessibility service if the services provide different feedback types. However, if two or more services provide the same feedback type, then only the first registered service receives the event.

注:如果服务提供不同反馈类型( feedback types),Android框架可以为无障碍事件分派一个以上的无障碍服务。但是,如果为两个或更多的服务提供相同的反馈类型,只有第一个注册的服务才能接收事件。

无障碍服务方法

An accessibility service must extend the AccessibilityService class and override the following methods from that class. These methods are presented in the order in which they are called by the Android system, from when the service is started (onServiceConnected()), while it is running (onAccessibilityEvent(), onInterrupt()) to when it is shut down (onUnbind()).

一个无障碍服务必须继承AccessibilityService类,重写该类的以下方法。这些方法被Android系统调用时按顺序呈现,从服务被启动(onServiceConnected()),一直运行(onAccessibilityEvent()onInterrupt()),到服务被关闭(onUnbind())。

  • onServiceConnected() - (optional) This system calls this method when it successfully connects to your accessibility service. Use this method to do any one-time setup steps for your service, including connecting to user feedback system services, such as the audio manager or device vibrator. If you want to set the configuration of your service at runtime or make one-time adjustments, this is a convenient location from which to call setServiceInfo().
    -(可选)当系统成功连接到无障碍服务时,调用该方法。使用该方法为无障碍服务提供任何一次性的启动步骤,包含连接到用户反馈系统服务,例如音频管理或设备震动。如果想要在应用运行时设置无障碍服务的配置或做一次性的调整,可以在该方法中调用setServiceInfo()来实现。
  • onAccessibilityEvent() - (required) This method is called back by the system when it detects an AccessibilityEvent that matches the event filtering parameters specified by your accessibility service. For example, when the user clicks a button or focuses on a user interface control in an application for which your accessibility service is providing feedback. When this happens, the system calls this method, passing the associated AccessibilityEvent, which the service can then interpret and use to provide feedback to the user. This method may be called many times over the lifecycle of your service.
    -(必选)当系统检测到一个符合无障碍服务设定的无障碍事件过滤参数的事件时,该方法被系统回调。例如,当用户在应用程序中点击一个按钮或聚焦一个用户界面控件时,你的无障碍服务会为此应用程序提供反馈。此时,系统调用这个方法,传递相关联的无障碍事件,无障碍服务就可以翻译和使用该事件为用户提供反馈。在无障碍服务的生命周期中,该方法会被调用多次。
  • onInterrupt() - (required) This method is called when the system wants to interrupt the feedback your service is providing, usually in response to a user action such as moving focus to a different control. This method may be called many times over the lifecycle of your service.
    - (必选)当系统想要打断无障碍服务提供的反馈时该方法被调用,一般情况下是响应用户操作,如移动焦点到一个不同的控件。在无障碍服务的生命周期中,该方法会被调用很多次。
  • onUnbind() - (optional) This method is called when the system is about to shutdown the accessibility service. Use this method to do any one-time shutdown procedures, including de-allocating user feedback system services, such as the audio manager or device vibrator.
    -(可选)当系统想要关闭无障碍服务的时候,调用该方法。使用该方法去完成一次性的关闭进程,包括解除分配用户反馈系统服务,例如音频管理或者设备震动。

These callback methods provide the basic structure for your accessibility service. It is up to you to decide on how to process data provided by the Android system in the form of AccessibilityEvent objects and provide feedback to the user. For more information about getting information from an accessibility event, see the Implementing Accessibility training.

这些回调方法为无障碍服务提供基本架构。在AccessibilityEvent对象中怎样处理由Android系统提供的数据并为用户提供反馈,是开发者自己决定的。获取无障碍事件信息的更多内容,详见实现无障碍(Implementing Accessibility)培训。

获得事件详情

The Android system provides information to accessibility services about the user interface interaction through AccessibilityEvent objects. Prior to Android 4.0, the information available in an accessibility event, while providing a significant amount of detail about a user interface control selected by the user, offered limited contextual information. In many cases, this missing context information might be critical to understanding the meaning of the selected control.

Android系统通过AccessibilityEvent对象为无障碍服务提供用户界面交互的信息。在Android4.0之前,可从无障碍事件中获得信息,且无障碍事件能够提供用户所选择的界面控件的大量详细信息,但这些信息仅包含有限的上下文信息。在很多情况下,丢失的上下文信息可能是理解已选定控件的意义的关键。

An example of an interface where context is critical is a calendar or day planner. If the user selects a 4:00 PM time slot in a Monday to Friday day list and the accessibility service announces “4 PM”, but does not announce the weekday name, the day of the month, or the month name, the resulting feedback is confusing. In this case, the context of a user interface control is critical to a user who wants to schedule a meeting.

一个界面的上下文是很关键,例如,日历或每日计划。如果用户选择周一到周五的下午四点,无障碍服务告知下午四点,但是没有说明是哪个工作日,哪个月的哪一天,反馈结果就会令人非常困扰。在这种情况下,用户界面控件的上下文对那些做时间规划的人非常关键。

Android 4.0 significantly extends the amount of information that an accessibility service can obtain about an user interface interaction by composing accessibility events based on the view hierarchy. A view hierarchy is the set of user interface components that contain the component (its parents) and the user interface elements that may be contained by that component (its children). In this way, the Android system can provide much richer detail about accessibility events, allowing accessibility services to provide more useful feedback to users.

Android4.0较大的扩展了无障碍服务能获取到的关于用户界面交互的信息量,这些信息是通过基于视图层次组合的无障碍事件提供。视图层次是用户界面元素的组合,该组合包含组件(父亲)和可能包含在其中的子元素(孩子)。因此,Android系统可以提供无障碍事件的更丰富的详细信息,允许无障碍服务为用户提供更多有用的反馈。

An accessibility service gets information about an user interface event through an AccessibilityEvent passed by the system to the service’s onAccessibilityEvent() callback method. This object provides details about the event, including the type of object being acted upon, its descriptive text and other details. Starting in Android 4.0 (and supported in previous releases through the AccessibilityEventCompat object in the Support Library), you can obtain additional information about the event using these calls:

系统将AccessibilityEvent传递到无障碍服务的onAccessibilityEvent()回调方法,因此,无障碍服务获得用户交互事件的信息。AccessibilityEvent会提供事件的详细信息,包含AccessibilityEvent的执行类型、描述文本和其他信息。从Android4.0开始(Android4.0以前的支持情况详见支持库(Support Library)中的AccessibilityEventCompat),可以通过调用以下方法获得更多信息。

  • AccessibilityEvent.getRecordCount()getRecord(int) - These methods allow you to retrieve the set of AccessibilityRecord objects which contributed to the AccessibilityEvent passed to you by the system. This level of detail provides more context for the event that triggered your accessibility service.
    -这些方法允许开发者获得一组AccessibilityRecord对象,该对象作为AccessibilityEvent的一部分,通过系统传递给开发者。该详情的级别为无障碍服务触发的事件提供了更多上下文信息。
  • AccessibilityEvent.getSource() - This method returns an AccessibilityNodeInfo object. This object allows you to request view layout hierarchy (parents and children) of the component that originated the accessibility event. This feature allows an accessibility service to investigate the full context of an event, including the content and state of any enclosing views or child views.
    - 该方法返回AccessibilityNodeInfo对象。该对象允许开发者请求查看触发无障碍事件的组件视图布局层次(父亲和孩子)。该特性允许无障碍服务访问事件的所有上下文内容,包含任何闭合视图或子视图的内容和状态。

    Important: The ability to investigate the view hierarchy from an AccessibilityEvent potentially exposes private user information to your accessibility service. For this reason, your service must request this level of access through the accessibility service configuration XML file, by including the canRetrieveWindowContent attribute and setting it to true. If you do not include this setting in your service configuration xml file, calls to getSource() fail.

    重要:从一个AccessibilityEvent访问视图层次的能力会将用户私人信息潜在的暴露给无障碍服务。基于该原因,无障碍服务必须在无障碍服务配置XML文件请求访问权限,该文件中需要包含canRetrieveWindowContent属性并将其设置为true。如果XML文件不包含这些设置,调用getSource()将会失败。

    Note: In Android 4.1 (API Level 16) and higher, the getSource() method, as well as AccessibilityNodeInfo.getChild() and getParent(), return only view objects that are considered important for accessibility (views that draw content or respond to user actions). If your service requires all views, it can request them by setting the flags member of the service's AccessibilityServiceInfo instance to FLAG_INCLUDE_NOT_IMPORTANT_VIEWS.

    注意:在Android4.1(API级别16)和以后的版本中,getSource()AccessibilityNodeInfo.getChild()getParent()方法,只返回一个对无障碍来说相当重要的视图对象(这些视图画有内容,或者响应用户操作)。如果无障碍服务针对所有视图,可以通过设置无障碍服务的AccessibilityServiceInfoflags成员来请求,详见flag中的非重要视图(FLAG_INCLUDE_NOT_IMPORTANT_VIEWS)。

为用户采取措施

Starting with Android 4.0 (API Level 14), accessibility services can act on behalf of users, including changing the input focus and selecting (activating) user interface elements. In Android 4.1 (API Level 16) the range of actions has been expanded to include scrolling lists and interacting with text fields. Accessibility services can also take global actions, such as navigating to the Home screen, pressing the Back button, opening the notifications screen and recent applications list. Android 4.1 also includes a new type of focus, Accessibilty Focus, which makes all visible elements selectable by an accessibility service.

从Android4.0(API级别14)开始,无障碍服务可以代表用户操作,包含改变输入焦点和选择(激活)用户界面元素。在Android4.1(API级别16),操作的范围被扩展至包含滚动列表和与文本域交互。无障碍服务也可采取全局操作,如导航到主界面、按返回按钮、打开屏幕通知和最近应用列表。Android4.1也包含新焦点类型,无障碍焦点,该焦点类型可让所有视觉元素能够被无障碍服务所选择。

These new capabilities make it possible for developers of accessibility services to create alternative navigation modes such as gesture navigation, and give users with disabilities improved control of their Android devices.

这些新的能力让开发者能够开发替代导航模式,如手势导航,提高残障用户对Android设备的控制。

手势监听

Accessibility services can listen for specific gestures and respond by taking action on behalf of a user. This feature, added in Android 4.1 (API Level 16), and requires that your accessibility service request activation of the Explore by Touch feature. Your service can request this activation by setting the flags member of the service’s AccessibilityServiceInfo instance to FLAG_REQUEST_TOUCH_EXPLORATION_MODE, as shown in the following example.

无障碍服务可以监听特定手势,并代表用户响应。该特性被添加在Android4.1(API级别16)版本中,要求无障碍服务激活触摸浏览特性。无障碍服务可以通过设置AccessibilityServiceInfo实例的flags成员为FLAG_REQUEST_TOUCH_EXPLORATION_MODE,请求该特性的激活,样例如下所示:

public class MyAccessibilityService extends AccessibilityService {
    @Override
    public void onCreate() {
        getServiceInfo().flags = AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE;
    }
    ...
}

Once your service has requested activation of Explore by Touch, the user must allow the feature to be turned on, if it is not already active. When this feature is active, your service receives notification of accessibility gestures through your service's onGesture() callback method and can respond by taking actions for the user.

一旦无障碍服务请求激活触摸浏览,如果该特性未打开,用户必须允许打开该特性。当该特性激活,无障碍服务将会通过onGesture()回调方法接收无障碍手势的通知,并且为用户响应操作。

使用无障碍操作

Accessibility services can take action on behalf of users to make interacting with applications simpler and more productive. The ability of accessibility services to perform actions was added in Android 4.0 (API Level 14) and significantly expanded with Android 4.1 (API Level 16).

无障碍服务可以代替用户操作,让用户与应用的交互更简单有效。无障碍服务的这个能力在Android4.0(API级别14)被加入,在Android4.1(API级别16)被显著扩展。

In order to take actions on behalf of users, your accessibility service must register to receive events from a few or many applications and request permission to view the content of applications by setting the android:canRetrieveWindowContent to true in the service configuration file. When events are received by your service, it can then retrieve the AccessibilityNodeInfo object from the event using getSource(). With the AccessibilityNodeInfo object, your service can then explore the view hierarchy to determine what action to take and then act for the user using performAction().

为了代替用户操作,无障碍服务必须注册来接收来自某些或者更多应用中的事件,并在无障碍服务配置文件中设置android:canRetrieveWindowContent属性为true,来请求查看应用程序的内容。当接收到事件,无障碍服务可以使用getSource()方法在事件中检索AccessibilityNodeInfo对象。使用AccessibilityNodeInfo对象你的无障碍服务可以浏览视图层次来判定采取什么操作并使用performAction()为用户操作。

public class MyAccessibilityService extends AccessibilityService {

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
       // 获得事件的资源节点
        AccessibilityNodeInfo nodeInfo = event.getSource();

        //使用事件和节点信息判定为用户执行什么样的操作。
        nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);

        //循环nodeInfo对象
        nodeInfo.recycle();
    }
    ...
}

The performAction() method allows your service to take action within an application. If your service needs to perform a global action such as navigating to the Home screen, pressing the Back button, opening the notifications screen or recent applications list, then use the performGlobalAction() method.

performAction()方法允许无障碍服务在应用中执行操作。如果无障碍服务需要去执行全局操作,例如导航到主屏幕、按返回键、打开屏幕通知或者最近应用列表等,使用performGlobalAction()方法。

使用焦点模式

Android 4.1 (API Level 16) introduces a new type of user interface focus called Accessibility Focus. Accessibility services can used this type of focus to select any visible user interface element and act on it. This focus type is different from the more well known Input Focus, which determines what on-screen user interface element receives input when a user types characters, presses Enter on a keyboard or pushes the center button of a D-pad control.

Android4.1(API级别16)引入了一种新的用户界面焦点,被称为无障碍焦点(Accessibility Focus)。这种类型的焦点可用于在无障碍服务中,选择任何视觉用户界面元素并操作该元素。该焦点类型不同于输入焦点(Input Focus)。当用户输入字符,点击键盘上的enter键或D-pad控制器的中心按钮时,输入焦点决定屏幕上哪个元素接收输入。

Accessibility Focus is completely separate and independent from Input Focus. In fact, it is possible for one element in a user interface to have Input Focus while another element has Accessibility Focus. The purpose of Accessibility Focus is to provide accessibility services with a method of interacting with any visible element on a screen, regardless of whether or not the element is input-focusable from a system perspective. You can see accessibility focus in action by testing accessibility gestures. For more information about testing this feature, see Testing gesture navigation.

无障碍焦点与输入焦点是完全分开和独立的。事实上,用户界面中的一个元素有输入焦点,同时另一个元素有无障碍焦点,这种情况是可能出现的。无障碍焦点的目的是,为无障碍服务提供一种与屏幕上视觉元素进行交互的方法,而不管该元素是否是系统层面的可输入聚焦元素。开发者可以在无障碍手势测试中看到无障碍焦点。更多关于该特性的信息,详见测试手势导航

Note: Accessibility services that use Accessibility Focus are responsible for synchronizing the current Input Focus when an element is capable of this type of focus. Services that do not synchronize Input Focus with Accessibility Focus run the risk of causing problems in applications that expect input focus to be in a specific location when certain actions are taken.

注:当元素具有输入焦点,使用无障碍焦点的无障碍服务有责任整合当前输入焦点。如果服务没有整合输入焦点和无障碍焦点,有可能会在应用中引起问题,问题是当采用特定操作时,需要将输入焦点固定在特定的位置。

An accessibility service can determine what user interface element has Input Focus or Accessibility Focus using the AccessibilityNodeInfo.findFocus() method. You can also search for elements that can be selected with Input Focus using the focusSearch() method. Finally, your accessibility service can set Accessibility Focus using the performAction(AccessibilityNodeInfo.ACTION_SET_ACCESSIBILITY_FOCUS) method.

无障碍服务可以使用AccessibilityNodeInfo.findFocus()方法来判定哪些用户界面元素有输入焦点或无障碍焦点,也可以使用focusSearch()方法来检索哪些元素可以用输入焦点选择。最后,可以使用performAction(AccessibilityNodeInfo.ACTION_SET_ACCESSIBILITY_FOCUS)方法来设置无障碍焦点。

样例代码

The API Demo project contains two samples which can be used as a starting point for generating accessibility services (<sdk>/samples/<platform>/ApiDemos/src/com/example/android/apis/accessibility):

API Demo项目包含两个样例,可以用来作为生成无障碍服务的起点 (<sdk>/samples/<platform>/ApiDemos/src/com/example/android/apis/accessibility):