android accessibility

主要介绍如开发作符合accessibility规范的应用,和开发自己的accessibility service。
一、 开发作符合accessibility规范的应用( Making Applications Accessible ) 
   主要有以下三点:
   1. Labeling User Interface Elements
       这点很简单,如果你都用android自带的控件(像TextView, Button等),大部分事情系统都帮你做了。你只需要在一些没有文字提示的控件(像ImageButton,ImageView,CheckBox等),使用 android:contentDescription属性,增加文字提示内容,如下代码:
          
              android:id=”@+id/add_note_button”    
              android:src=”@drawable/add_note”    
              android:contentDescription=”@string/add_note”/>
   AccessibilityService可以通过调用getContentDescription来获取contentDescription的内容。
 2. Enabling Focus Navigation
     这点也很简单,就是要保证你所有需要操作的控件,都可以方向键导航来换取焦点。
3. Building Accessible Custom Views
   如果使用自定义accessibility控件的话,就需要自己处理accessibility 事件。了解自定义accessibility控件的方法,有助于理解accessibility框架的原理。
   自定义accessibility控件主要包含以下4点:
    (1) Handle directional controller clicks
         在获取焦点的View,接收到ok键或回车键的时候,需要执行点击事件的行为。
    (2)Implement accessibility API methods
         主要有以下四个方法(第4点会更详细介绍):
          dispatchPopulateAccessibilityEvent()
         onPopulateAccessibilityEvent()
         onInitializeAccessibilityEvent()
         onInitializeAccessibilityNodeInfo()

    (3)Send AccessibilityEvent objects specific to your custom view
        比如说,在你定制的控件获取焦点的时候,调用View.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED)等。

    (4)Populate AccessibilityEvent and AccessibilityNodeInfo for your view
        构建 AccessibilityEvent和 AccessibilityNodeInfo。这一点比较重要,因为如果我们开发accessibility service的时候,需要用到Accessibility和AccessibilityNodeInfo来获取accessibility 的消息。
         先来看看   AccessibilityNodeInfo的构造。 看第(2)点的的四个函数。 onInitializeAccessibilityNodeInfo()用来初始化   AccessibilityNodeInfo。它会根据View的层次填充子View的   AccessibilityNodeInfo和父View的   AccessibilityNodeInfo。比如一个LinearLayout里面放置了两个Button,在回调LinearLayout的 onInitializeAccessibilityNodeInfo()的时候,就会给LinearLayout的   AccessibilityNodeInfo填充上两个子View的   AccessibilityNodeInfo。所以,你可以通过event.getSource()获取到一个和View的层次结构类似的树形   AccessibilityNodeInfo。  
         再来看看 AccessibilityEvent的构造。看第(2)点第三个函数。 onInitializeAccessibilityEvent()用来初始化AccessibilityEvent的一些属性,如设置className,设置是否被选中等等。可以去看api说明,获取完整的设置属性。除了属性之外,还有一个非常重要的内容,就是accessibility的提示消息。主要通过   dispatchPopulateAccessibilityEvent()和 onPopulateAccessibilityEvent()这两个函数来获取的。看下图:
       android accessibility_第1张图片
         这是 AccessibilityEvent.getText()的填充过程。getText()返回的是一个字符数组。可以看到,ViewGroup调用dispatchPopulateAccessibilityEvent之后,会触发自身的onPopulateAccessibilityEvent函数。在这个函数里,可以调用event.getText().add(String)的方法来填充数据。接下来就会遍历所有的子View,调用每个子View的 dispatchPopulateAccessibilityEvent方法,然后 dispatchPopulateAccessibilityEvent触发自身的 onPopulateAccessibilityEvent函数。同样, 在这个函数里,可以调用event.getText().add(String)的方法来填充数据。这边有一点要强调一下,ViewGroup和View的AccessibilityEvent是同一个event。这样子,你就可以获取ViewGroup及其所有子View的accessibility消息了。

二、开发自己的accessibility service( Building Accessibility Services ).
    主要有以下五点:
    1.  Manifest Declarations and Permissions
        看下面例子:

  ...
 
  ...
 
    ...
      android:name =". MyAccessibilityService "
       
  android:label ="@string/ accessibility_service_label "
       
  android:permission =" android.permission.BIND_ACCESSIBILITY_SERVICE ">
     
       
    android:name =" android.accessibilityservice.AccessibilityService " />
     

                    android:name="android.accessibilityservice"
       android:resource="@xml/accessibility_service_config"
  />
   
      android:name =" android.permission.BIND_ACCESSIBILITY_SERVICE " />
 
      
           红色字体是需要添加的权限和intent-filter,绿色字体是配置文件的信息。配置文件看以下例子:
  xmlns:android ="http://schemas.android.com/apk/res/android"
   
  android:description ="@string/ accessibility_service_description

              android:canRequestFilterKeyEvents="true" 
   
 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 事件。表明只接收 com.example.android.apis这个应用的所有accessibility时间。当然,这两个属性可以在运行时改变。其他属性可以去参考api文档。  
    2. Registering for Accessibility Events
     如上面例子,可以通过包名和事件来过滤AccessibilityEvent.
    3. AccessibilityService Methods
      主要有以下四个方法:
       onServiceConnected():可以用来初始化操作,如初始化TTS,设置accessibilityEvent的过滤条件等。 
      onAccessibilityEvent():接收你注册的accessibility事件。
      onInterrupt():看以下官方解释: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()。我的理解是,系统中断你的accessibility service回馈的时候调用。例如,你用TTS语言提示一个accessibility 消息的时候,还没提示完,又来的一个accessibility event,这时候,正在播报的事件就会被中断,就会回调这个函数。但是,在我实际开发过程中,没有用到这个函数。我开发的也是用TTS提示,需要中断的话,会调用TTS的Tts.speak(text,  TextToSpeech.QUEUE_FLUSH , null,null),TTS自己会中断之前的提示,无需用到onInterrupt()方法。
      onUnbind():在accessibility service关闭的时候调用。用来清除一些系统资源等。和onSerciceConnected相对应。

    4. Getting Event Details
       这是在系统回调 onAccessibilityEvent()的时候获取的,主要有两个数据:
        AccessibilityEvent:在 onAccessibilityEvent()的参数列表里。参照之前自定义accessibility View的章节,调用event.getText()来获取accessibility消息,还可以调用其他方法获取包名类名等消息。具体方法参照文档。
       AccessibilityNodeInfo:主要用来遍历View的AccessibilityNodeInfo信息。参考之前自定义accessibility View的章节,调用AccessibilityEvent.getSource()获取当前View的 AccessibilityNodeInfo , 通过 AccessibilityNodeInfo.getChild(index)和 AccessibilityNodeInfo. getParent()获取子View和父View的 AccessibilityNodeInfo。   

    5. Taking Action for Users
       accessibility service也可以执行一些操作,如让View获取焦点等,通过调用 AccessibilityNodeInfo. performAction()来实现。也可以执行一些全局的操作,如回到launcher等,通过调用 AccessibilityService.performGlobalAction()来实现。









你可能感兴趣的:(android)