blob: da24d03adf606354b3da90cabc4c6ce6606c3439 [file] [log] [blame]
page.title=Making Applications Accessible
parent.title=Accessibility
parent.link=index.html
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
<ol>
<li><a href="#label-ui">Labeling User Interface Elements</a></li>
<li><a href="#focus-nav">Enabling Focus Navigation</a>
<ol>
<li><a href="#focus-enable">Enabling view focus</a></li>
<li><a href="#focus-order">Controlling focus order</a></li>
</ol>
</li>
<li><a href="#custom-views">Building Accessible Custom Views</a>
<ol>
<li><a href="#directional-control">Handling directional controller clicks</a></li>
<li><a href="#accessibility-methods">Implementing accessibility API methods</a></li>
<li><a href="#send-events">Sending accessibility events</a></li>
<li><a href="#populate-events">Populating accessibility events</a></li>
<li><a href="#virtual-hierarchy">Providing a customized accessibility context</a></li>
<li><a href="#custom-touch-events">Handling custom touch events</a></li>
</ol>
</li>
<li><a href="#test">Testing Accessibility</a></li>
</ol>
<h2>Key classes</h2>
<ol>
<li>{@link android.view.accessibility.AccessibilityEvent}</li>
<li>{@link android.view.accessibility.AccessibilityNodeInfo}</li>
<li>{@link android.support.v4.view.accessibility.AccessibilityNodeInfoCompat}</li>
<li>{@link android.view.View.AccessibilityDelegate}</li>
<li>{@link android.support.v4.view.AccessibilityDelegateCompat}</li>
</ol>
<h2>See also</h2>
<ol>
<li><a href="checklist.html">Accessibility Developer Checklist</a><li>
<li><a href="{@docRoot}tools/testing/testing_accessibility.html">Accessibility Testing Checklist</a><li>
<li><a href="{@docRoot}design/patterns/accessibility.html">Android Design: Accessibility</a></li>
<li><a href="{@docRoot}training/design-navigation/index.html">Designing Effective Navigation</a></li>
<li><a href="{@docRoot}training/accessibility/index.html">Training: Implementing Accessibility</a></li>
</ol>
</div>
</div>
<p>Applications built for Android are more accessible to users with visual, physical or age-related
limitations when those users activate accessibility services and features on a device. These
services make your application more accessible even if you do not make any accessibility changes
to your code. However, there are steps you should take to optimize the accessibility of your
application and ensure a pleasant experience for all your users.</p>
<p>Making sure your application is accessible to all users requires only a few steps, particularly
when you create your user interface with the components provided by the Android framework. If you
use only the standard components for your application, the steps are:</p>
<ol>
<li>Add descriptive text to user interface controls in your application using the
<a href="{@docRoot}reference/android/view/View.html#attr_android:contentDescription">
{@code android:contentDescription}</a> attribute. Pay particular attention to
{@link android.widget.ImageButton}, {@link android.widget.ImageView}
and {@link android.widget.CheckBox}.</li>
<li>Make sure that all user interface elements that can accept input (touches or typing) can be
reached with a directional controller, such as a trackball, D-pad (physical or virtual) or
navigation <a href="http://support.google.com/android/bin/topic.py?hl=en&topic=2492346">gestures
</a>.</li>
<li>Make sure that audio prompts are always accompanied by another visual prompt or notification,
to assist users who are deaf or hard of hearing.</li>
<li>Test your application using only accessibility navigation services and features. Turn on
<a href="{@docRoot}tools/testing/testing_accessibility.html#testing-talkback">TalkBack</a> and
<a href="{@docRoot}tools/testing/testing_accessibility.html#testing-ebt">Explore by Touch</a>,
and then try using your application using only directional controls. For more information on
testing for accessibility, see the <a href="{@docRoot}tools/testing/testing_accessibility.html">
Accessibility Testing Checklist</a>.</li>
</ol>
<p>If you build custom controls that extend the {@link android.view.View} class, you must complete
some additional work to make sure your components are accessible. This document discusses how to
make custom view controls compatible with accessibility services.</p>
<p class="note">
<strong>Note:</strong> The implementation steps in this document describe the requirements for
making your application accessible for users with blindness or low-vision. Be sure to review the
requirements for serving users who are deaf and hard of hearing in the
<a href="{@docRoot}guide/topics/ui/accessibility/checklist.html">Accessibility Developer
Checklist</a></p>.
<h2 id="label-ui">Labeling User Interface Elements</h2>
<p>Many user interface controls depend on visual cues to indicate their meaning and usage. For
example, a note-taking application might use an {@link android.widget.ImageButton} with a
picture of a plus sign to indicate that the user can add a new note. An {@link
android.widget.EditText} component may have a label near it that indicates its purpose. A user
with impaired vision can't see these cues well enough to follow them, which makes them useless.</p>
<p>You can make these controls more accessible with the
<a href="{@docRoot}reference/android/view/View.html#attr_android:contentDescription">
{@code android:contentDescription}</a> XML layout attribute. The text in this attribute does not
appear on screen, but if the user enables accessibility services that provide audible prompts, then
when the user navigates to that control, the text is spoken.</p>
<p>For this reason, set the
<a href="{@docRoot}reference/android/view/View.html#attr_android:contentDescription">
{@code android:contentDescription}</a> attribute for every {@link android.widget.ImageButton},
{@link android.widget.ImageView}, {@link android.widget.CheckBox}
in your application's user interface, and add descriptions to any other input controls that might
require additional information for users who are not able to see it.</p>
<p>For example, the following {@link android.widget.ImageButton} sets the content description for
the plus button to the {@code add_note} string resource, which could be defined as “Add note" for an
English language interface:</p>
<pre>
&lt;ImageButton
android:id=”@+id/add_note_button”
android:src=”@drawable/add_note”
android:contentDescription=”@string/add_note”/&gt;
</pre>
<p>By including the description, an accessibility service that provides spoken feedback can announce
"Add note" when a user moves focus to this button or hovers over it.</p>
<p class="note"><strong>Note:</strong> For {@link android.widget.EditText} fields, provide an
<a href="{@docRoot}reference/android/widget/TextView.html#attr_android:hint">android:hint</a>
attribute <em>instead</em> of a content description, to help users understand what content is
expected when the text field is empty. When the field is filled, TalkBack reads the entered
content to the user, instead of the hint text.</p>
<h2 id="focus-nav">Enabling Focus Navigation</h2>
<p>Focus navigation allows users with disabilities to step through user interface controls using a
directional controller. Directional controllers can be physical, such as a trackball, directional
pad (D-pad) or arrow keys, or virtual, such as the
<a href="https://play.google.com/store/apps/details?id=com.googlecode.eyesfree.inputmethod.latin">
Eyes-Free Keyboard</a>, or the gestures navigation mode available in Android 4.1 and higher.
Directional controllers are a primary means of navigation for many Android users.
</p>
<p>To ensure that users can navigate your application using only a directional controller, verify
that all user interface (UI) input controls in your application can be reached and activated
without using the touchscreen. You should also verify that clicking with the center button (or OK
button) of a directional controller has the same effect as touching a control that already has
focus. For information on testing directional controls, see
<a href="{@docRoot}tools/testing/testing_accessibility.html#test-navigation">Testing
focus navigation</a>.</p>
<h3 id="focus-enable">Enabling view focus</h3>
<p>A user interface element is reachable using directional controls when its
<a href="{@docRoot}reference/android/view/View.html#attr_android:focusable">
{@code android:focusable}</a> attribute is set to {@code true}. This setting allows users to focus
on the element using the directional controls and then interact with it. The user interface controls
provided by the Android framework are focusable by default and visually indicate focus by changing
the control’s appearance.</p>
<p>Android provides several APIs that let you control whether a user interface control is focusable
and even request that a control be given focus:</p>
<ul>
<li>{@link android.view.View#setFocusable setFocusable()}</li>
<li>{@link android.view.View#isFocusable isFocusable()}</li>
<li>{@link android.view.View#requestFocus requestFocus()}</li>
</ul>
<p>If a view is not focusable by default, you can make it focusable in your layout file by setting
the <a href="{@docRoot}reference/android/view/View.html#attr_android:focusable">
{@code android:focusable}</a> attribute to {@code true} or by calling the its {@link
android.view.View#setFocusable setFocusable()} method.</p>
<h3 id="focus-order">Controlling focus order</h3>
<p>When users navigate in any direction using directional controls, focus is passed from one
user interface element (view) to another, as determined by the focus order. This order is based on
an algorithm that finds the nearest neighbor in a given direction. In rare cases, the algorithm may
not match the order that you intended or may not be logical for users. In these situations, you can
provide explicit overrides to the ordering using the following XML attributes in your layout file:
</p>
<dl>
<dt><a href="{@docRoot}reference/android/view/View.html#attr_android:nextFocusDown">
{@code android:nextFocusDown}</a></dt>
<dd>Defines the next view to receive focus when the user navigates down.</dd>
<dt><a href="{@docRoot}reference/android/view/View.html#attr_android:nextFocusLeft">
{@code android:nextFocusLeft}</a></dt>
<dd>Defines the next view to receive focus when the user navigates left.</dd>
<dt><a href="{@docRoot}reference/android/view/View.html#attr_android:nextFocusRight">
{@code android:nextFocusRight}</a></dt>
<dd>Defines the next view to receive focus when the user navigates right.</dd>
<dt><a href="{@docRoot}reference/android/view/View.html#attr_android:nextFocusUp">
{@code android:nextFocusUp}</a></dt>
<dd>Defines the next view to receive focus when the user navigates up.</dd>
</dl>
<p>The following example XML layout shows two focusable user interface elements where the
<a href="{@docRoot}reference/android/view/View.html#attr_android:nextFocusDown">{@code
android:nextFocusDown}</a> and
<a href="{@docRoot}reference/android/view/View.html#attr_android:nextFocusUp">{@code
android:nextFocusUp}</a> attributes have been explicitly set. The {@link android.widget.TextView} is
located to the right of the {@link android.widget.EditText}. However, since these properties have
been set, the {@link android.widget.TextView} element can now be reached by pressing the down arrow
when focus is on the {@link android.widget.EditText} element:</p>
<pre>
&lt;LinearLayout android:orientation="horizontal"
... &gt;
&lt;EditText android:id="@+id/edit"
android:nextFocusDown=”@+id/text”
... /&gt;
&lt;TextView android:id="@+id/text"
android:focusable=”true”
android:text="Hello, I am a focusable TextView"
android:nextFocusUp=”@id/edit”
... /&gt;
&lt;/LinearLayout&gt;
</pre>
<p>When modifying focus order, be sure that the navigation works as expected in all directions from
each user interface control and when navigating in reverse (to get back to where you came from).</p>
<p class="note"><strong>Note:</strong> You can modify the focus order of user interface components
at runtime, using methods such as {@link android.view.View#setNextFocusDownId setNextFocusDownId()}
and {@link android.view.View#setNextFocusRightId setNextFocusRightId()}.</p>
<h2 id="custom-views">Building Accessible Custom Views</h2>
<p>If your application requires a <a href="{@docRoot}guide/topics/ui/custom-components.html">custom
view component</a>, you must do some additional work to ensure that your custom view is accessible.
These are the main tasks for ensuring the accessibility of your view:</p>
<ul>
<li>Handle directional controller clicks</li>
<li>Implement accessibility API methods</li>
<li>Send {@link android.view.accessibility.AccessibilityEvent} objects specific to your custom
view</li>
<li>Populate {@link android.view.accessibility.AccessibilityEvent} and {@link
android.view.accessibility.AccessibilityNodeInfo} for your view</li>
</ul>
<h3 id="directional-control">Handling directional controller clicks</h3>
<p>On most devices, clicking a view using a directional controller sends a {@link
android.view.KeyEvent} with {@link android.view.KeyEvent#KEYCODE_DPAD_CENTER} to the view currently
in focus. All standard Android views already handle {@link
android.view.KeyEvent#KEYCODE_DPAD_CENTER} appropriately. When building a custom {@link
android.view.View} control, make sure this event has the same effect as touching the view on the
touchscreen. </p>
<p>Your custom control should also treat the {@link android.view.KeyEvent#KEYCODE_ENTER} event the
same as {@link android.view.KeyEvent#KEYCODE_DPAD_CENTER}. This approach makes interaction from a
full keyboard much easier for users.</p>
<h3 id="accessibility-methods">Implementing accessibility API methods</h3>
<p>Accessibility events are messages about users interaction with visual interface components in
your application. These messages are handled by <a href="services.html">Accessibility Services</a>,
which use the information in these events to produce supplemental feedback and prompts. In
Android 4.0 (API Level 14) and higher, the methods for
generating accessibility events have been expanded to provide more detailed information than the
{@link android.view.accessibility.AccessibilityEventSource} interface introduced in Android 1.6 (API
Level 4). The expanded accessibility methods are part of the {@link android.view.View} class as well
as the {@link android.view.View.AccessibilityDelegate} class. The methods are as follows:</p>
<dl>
<dt>{@link android.view.View#sendAccessibilityEvent sendAccessibilityEvent()}</dt>
<dd>(API Level 4) This method is called when a user takes action on a view. The event is
classified with a user action type such as {@link
android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED TYPE_VIEW_CLICKED}. You typically do
not need to implement this method unless you are creating a custom view.</dd>
<dt>{@link android.view.View#sendAccessibilityEventUnchecked
sendAccessibilityEventUnchecked()}</dt>
<dd>(API Level 4) This method is used when the calling code needs to directly control the check
for accessibility being enabled on the device ({@link
android.view.accessibility.AccessibilityManager#isEnabled AccessibilityManager.isEnabled()}). If
you do implement this method, you must perform the call as if accessibility is enabled, regardless
of the actual system setting. You typically do not need to implement this method for a custom view.
</dd>
<dt>{@link android.view.View#dispatchPopulateAccessibilityEvent
dispatchPopulateAccessibilityEvent()}</dt>
<dd>(API Level 4) The system calls this method when your custom view generates an
accessibility event. As of API Level 14, the default implementation of this method calls {@link
android.view.View#onPopulateAccessibilityEvent onPopulateAccessibilityEvent()} for this view and
then the {@link android.view.View#dispatchPopulateAccessibilityEvent
dispatchPopulateAccessibilityEvent()} method for each child of this view. In order to support
accessibility services on revisions of Android <em>prior</em> to 4.0 (API Level 14) you
<em>must</em> override this method and populate {@link
android.view.accessibility.AccessibilityEvent#getText} with descriptive text for your custom
view, which is spoken by accessibility services, such as TalkBack.</dd>
<dt>{@link android.view.View#onPopulateAccessibilityEvent onPopulateAccessibilityEvent()}</dt>
<dd>(API Level 14) This method sets the spoken text prompt of the {@link
android.view.accessibility.AccessibilityEvent} for your view. This method is also called if the
view is a child of a view which generates an accessibility event.
<p class="note"><strong>Note:</strong> Modifying additional attributes beyond the text within
this method potentially overwrites properties set by other methods. While you can modify
attributes of the accessibility event with this method, you should limit these changes
to text content, and use the {@link android.view.View#onInitializeAccessibilityEvent
onInitializeAccessibilityEvent()} method to modify other properties of the event.</p>
<p class="note"><strong>Note:</strong> If your implementation of this event completely
overrides the output text without allowing other parts of your layout to modify its content, then
do not call the super implementation of this method in your code.</p>
</dd>
<dt>{@link android.view.View#onInitializeAccessibilityEvent onInitializeAccessibilityEvent()}</dt>
<dd>(API Level 14) The system calls this method to obtain additional information about the
state of the view, beyond text content. If your custom view provides interactive control beyond a
simple {@link android.widget.TextView} or {@link android.widget.Button}, you should override this
method and set the additional information about your view into the event using this method, such as
password field type, checkbox type or states that provide user interaction or feedback. If you
do override this method, you must call its super implementation and then only modify properties
that have not been set by the super class.</dd>
<dt>{@link android.view.View#onInitializeAccessibilityNodeInfo
onInitializeAccessibilityNodeInfo()}</dt>
<dd>(API Level 14) This method provides accessibility services with information about the state of
the view. The default {@link android.view.View} implementation has a standard set of view
properties, but if your custom view provides interactive control beyond a simple {@link
android.widget.TextView} or {@link android.widget.Button}, you should override this method and set
the additional information about your view into the {@link
android.view.accessibility.AccessibilityNodeInfo} object handled by this method.</dd>
<dt>{@link android.view.ViewGroup#onRequestSendAccessibilityEvent
onRequestSendAccessibilityEvent()}</dt>
<dd>(API Level 14) The system calls this method when a child of your view has generated an
{@link android.view.accessibility.AccessibilityEvent}. This step allows the parent view to amend
the accessibility event with additional information. You should implement this method only if your
custom view can have child views and if the parent view can provide context information to the
accessibility event that would be useful to accessibility services.</dd>
</dl>
<p>In order to support these accessibility methods for a custom view, you should take one of the
following approaches:</p>
<ul>
<li>If your application targets Android 4.0 (API level 14) and higher, override and implement the
accessibility methods listed above directly in your custom view class.</li>
<li>If your custom view is intended to be compatible with Android 1.6 (API Level 4) and above, add
the Android <a href="{@docRoot}tools/support-library/index.html">Support Library</a>, revision 5 or
higher, to your project. Then, within your custom view class, call the
{@link android.support.v4.view.ViewCompat#setAccessibilityDelegate
ViewCompat.setAccessibilityDelegate()} method to implement the accessibility methods
above. For an example of this approach, see the Android Support Library (revision 5 or higher)
sample {@code AccessibilityDelegateSupportActivity} in
({@code &lt;sdk&gt;/extras/android/support/v4/samples/Support4Demos/})
</li>
</ul>
<p>In either case, you should implement the following accessibility methods for your custom view
class:</p>
<ul>
<li>{@link android.view.View#dispatchPopulateAccessibilityEvent
dispatchPopulateAccessibilityEvent()}</li>
<li>{@link android.view.View#onPopulateAccessibilityEvent
onPopulateAccessibilityEvent()}</li>
<li>{@link android.view.View#onInitializeAccessibilityEvent
onInitializeAccessibilityEvent()}</li>
<li>{@link android.view.View#onInitializeAccessibilityNodeInfo
onInitializeAccessibilityNodeInfo()}</li>
</ul>
<p>For more information about implementing these methods, see <a href="#populate-events">Populating
Accessibility Events</a>.</p>
<h3 id="send-events">Sending accessibility events</h3>
<p>Depending on the specifics of your custom view, it may need to send {@link
android.view.accessibility.AccessibilityEvent} objects at a different times or for events not
handled by the default implementation. The {@link android.view.View} class provides a default
implementation for these event types:</p>
<ul>
<li>Starting with API Level 4:
<ul>
<li>{@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED}</li>
<li>{@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_LONG_CLICKED}</li>
<li>{@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_FOCUSED}</li>
</ul>
</li>
<li>Starting with API Level 14:
<ul>
<li>{@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SCROLLED}</li>
<li>{@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}</li>
<li>{@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}</li>
</ul>
</li>
</ul>
<p class="note"><strong>Note:</strong> Hover events are associated with the Explore by
Touch feature, which uses these events as triggers for providing audible prompts for user interface
elements.</p>
<p>In general, you should send an {@link android.view.accessibility.AccessibilityEvent} whenever the
content of your custom view changes. For example, if you are implementing a custom slider bar that
allows a user to select a numeric value by pressing the left or right arrows, your custom view
should emit an event of type {@link
android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED} whenever the slider
value changes. The following sample code demonstrates the use of the {@link
android.view.accessibility.AccessibilityEventSource#sendAccessibilityEvent
sendAccessibilityEvent()} method to report this event.</p>
<pre>
&#64;Override
public boolean onKeyUp (int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
mCurrentValue--;
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
return true;
}
...
}
</pre>
<h3 id="populate-events">Populating accessibility events</h3>
<p>Each {@link android.view.accessibility.AccessibilityEvent} has a set of required properties that
describe the current state of the view. These properties include things such as the view’s class
name, content description and checked state. The specific properties required for each event type
are described in the {@link android.view.accessibility.AccessibilityEvent} reference documentation.
The {@link android.view.View} implementation provides default values for these properties. Many of
these values, including the class name and event timestamp, are provided automatically. If you are
creating a custom view component, you must provide some information about the content and
characteristics of the view. This information may be as simple as a button label, but may also
include additional state information that you want to add to the event.</p>
<p>The minimum requirement for providing information to accessibility services with a custom
view is to implement {@link android.view.View#dispatchPopulateAccessibilityEvent
dispatchPopulateAccessibilityEvent()}. This method is called by the system to request
information for an {@link android.view.accessibility.AccessibilityEvent} and makes your custom
view compatible with accessibility services on Android 1.6 (API Level 4) and higher. The
following example code demonstrates a basic implementation of this method.</p>
<pre>
&#64;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);
}
}
</pre>
<p>For Android 4.0 (API Level 14) and higher, use the {@link
android.view.View#onPopulateAccessibilityEvent onPopulateAccessibilityEvent()} and
{@link android.view.View#onInitializeAccessibilityEvent onInitializeAccessibilityEvent()}
methods to populate or modify the information in an {@link
android.view.accessibility.AccessibilityEvent}. Use the
{@link android.view.View#onPopulateAccessibilityEvent onPopulateAccessibilityEvent()} method
specifically for adding or modifying the text content of the event, which is turned into audible
prompts by accessibility services such as TalkBack. Use the
{@link android.view.View#onInitializeAccessibilityEvent onInitializeAccessibilityEvent()} method for
populating additional information about the event, such as the selection state of the view.</p>
<p>In addition, implement the
{@link android.view.View#onInitializeAccessibilityNodeInfo onInitializeAccessibilityNodeInfo()}
method. The {@link android.view.accessibility.AccessibilityNodeInfo} objects populated by this method
are used by accessibility services to investigate the view hierarchy that generated an accessibility
event after receiving that event, to obtain a more detailed context information and provide
appropriate feedback to users.</p>
<p>The example code below shows how override these three methods by using
{@link android.support.v4.view.ViewCompat#setAccessibilityDelegate
ViewCompat.setAccessibilityDelegate()}. Note that this sample code requires that the Android
<a href="{@docRoot}tools/support-library/index.html">Support Library</a> for API Level 4 (revision
5 or higher) is added to your project.</p>
<pre>
ViewCompat.setAccessibilityDelegate(new AccessibilityDelegateCompat() {
&#64;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);
}
}
&#64;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());
}
&#64;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);
}
}
}
</pre>
<p>In applications targeting Android 4.0 (API Level 14) and higher, you can implement these methods
directly in your custom view class. For another example of this approach, see the Android
<a href="{@docRoot}tools/support-library/index.html">Support Library</a> (revision 5 or higher)
sample {@code AccessibilityDelegateSupportActivity} in
({@code &lt;sdk&gt;/extras/android/support/v4/samples/Support4Demos/}).</p>
<p class="note"><strong>Note:</strong> You may find information on implementing accessibility for
custom views written prior to Android 4.0 that describes the use of the
{@link android.view.View#dispatchPopulateAccessibilityEvent dispatchPopulateAccessibilityEvent()}
method for populating AccessibilityEvents. As of the Android 4.0 release, however, the recommended
approach is to use the
{@link android.view.View#onPopulateAccessibilityEvent onPopulateAccessibilityEvent()} and
{@link android.view.View#onInitializeAccessibilityEvent onInitializeAccessibilityEvent()}
methods.</p>
<h3 id="virtual-hierarchy">Providing a customized accessibility context</h3>
<p>In Android 4.0 (API Level 14), the framework was enhanced to allow accessibility services to
inspect the containing view hierarchy of a user interface component that generates an
accessibility event. This enhancement allows accessibility services to provide a much richer set
of contextual information with which to aid users.</p>
<p>There are some cases where accessibility services cannot get adequate information
from the view hierarchy. An example of this is a custom interface control that has two or more
separately clickable areas, such as a calendar control. In this case, the services cannot get
adequate information because the clickable subsections are not part of the view hierarchy.</p>
<img src="calendar.png" alt="" id="figure1" />
<p class="img-caption">
<strong>Figure 1.</strong> A custom calendar view with selectable day elements.
</p>
<p>In the example shown in Figure 1, the entire calendar is implemented as a single view, so if you
do not do anything else, accessibility services do not receive enough information about the
content of the view and the user's selection within the view. For example, if a user clicks on the
day containing <strong>17</strong>, the accessibility framework only receives the description
information for the whole calendar control. In this case, the TalkBack accessibility service would
simply announce "Calendar" or, only slightly better, "April Calendar" and the user would be left
to wonder what day was selected.</p>
<p>To provide adequate context information for accessibility services in situations like this,
the framework provides a way to specify a virtual view hierarchy. A <em>virtual view
hierarchy</em> is a way for application developers to provide a complementary view hierarchy
to accessibility services that more closely matches the actual information on screen. This
approach allows accessibility services to provide more useful context information to users.</p>
<p>Another situation where a virtual view hierarchy may be needed is a user interface containing
a set of controls (views) that have closely related functions, where an action on one control
affects the contents of one or more elements, such as a number picker with separate up and down
buttons. In this case, accessibility services cannot get adequate information because action on
one control changes content in another and the relationship of those controls may not be apparent
to the service. To handle this situation, group the related controls with a containing view and
provide a virtual view hierarchy from this container to clearly represent the information and
behavior provided by the controls.</p>
<p>In order to provide a virtual view hierarchy for a view, override the {@link
android.view.View#getAccessibilityNodeProvider} method in your custom view or view group and
return an implementation of {@link android.view.accessibility.AccessibilityNodeProvider}. For an
example implementation of this accessibility feature, see
{@code AccessibilityNodeProviderActivity} in the ApiDemos sample project. You can implement a
virtual view hierarchy that is compatible with Android 1.6 and later by using the
<a href="{@docRoot}tools/support-library/index.html">Support Library</a> with the
{@link android.support.v4.view.ViewCompat#getAccessibilityNodeProvider
ViewCompat.getAccessibilityNodeProvider()} method and providing an implementation with
{@link android.support.v4.view.accessibility.AccessibilityNodeProviderCompat}.</p>
<h3 id="custom-touch-events">Handling custom touch events</h3>
<p>Custom view controls may require non-standard touch event behavior. For example, a custom
control may use the {@link android.view.View#onTouchEvent} listener method to detect the
{@link android.view.MotionEvent#ACTION_DOWN} and {@link android.view.MotionEvent#ACTION_UP} events
and trigger a special click event. In order to maintain compatibility with accessibility services,
the code that handles this custom click event must do the following:</p>
<ol>
<li>Generate an appropriate {@link android.view.accessibility.AccessibilityEvent} for the
interpreted click action.</li>
<li>Enable accessibility services to perform the custom click action for users who are not able to
use a touch screen.</li>
</ol>
<p>To handle these requirements in an efficient way, your code should override the
{@link android.view.View#performClick} method, which must call the super implementation of this
method and then execute whatever actions are required by the click event. When the custom click
action is detected, that code should then call your {@code performClick()} method. The following
code example demonstrates this pattern.</p>
<pre>
class CustomTouchView extends View {
public CustomTouchView(Context context) {
super(context);
}
boolean mDownTouch = false;
&#64;Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
// Listening for the down and up touch events
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownTouch = true;
return true;
case MotionEvent.ACTION_UP:
if (mDownTouch) {
mDownTouch = false;
performClick(); // Call this method to handle the response, and
// thereby enable accessibility services to
// perform this action for a user who cannot
// click the touchscreen.
return true;
}
}
return false; // Return false for other touch events
}
&#64;Override
public boolean performClick() {
// Calls the super implementation, which generates an AccessibilityEvent
// and calls the onClick() listener on the view, if any
super.performClick();
// Handle the action for the custom click here
return true;
}
}
</pre>
<p>The pattern shown above makes sure that the custom click event is compatible with
accessibility services by using the {@link android.view.View#performClick} method to both generate
an accessibility event and provide an entry point for accessibility services to act on behalf of a
user to perform this custom click event.</p>
<p class="note"><strong>Note:</strong> If your custom view has distinct clickable regions, such as
a custom calendar view, you must implement a <a href="#virtual-hierarchy">virtual view
hierarchy</a> by overriding {@link android.view.View#getAccessibilityNodeProvider} in your custom
view in order to be compatible with accessibility services.</p>
<h2 id="test">Testing Accessibility</h2>
<p>Testing the accessibility of your application is an important part of ensuring your users have a
great experience. You can test the most important accessibility features by using your application
with audible feedback enabled and navigating within your application using only directional
controls. For more information on testing accessibility in your application, see the
<a href="{@docRoot}tools/testing/testing_accessibility.html">Accessibility Testing Checklist</a>.
</p>