Applications built for Android are accessible to users with visual, physical or age-related disabilities when they activate accessibility features and services on a device. By default, these services make your application more accessible. However, there are further steps you should take to optimize the accessibility of your application and ensure a pleasant experience for all your users.
Making sure your application is accessible to all users is relatively easy, particularly when you use framework-provided user interface components. If you only use these standard components for your application, there are just a few steps required to ensure your application is accessible:
- Label your
ImageButton
,ImageView
,EditText
,CheckBox
and other user interface controls using theandroid:contentDescription
attribute. - Make all of your user interface elements accessible with a directional controller, such as a trackball or D-pad.
- Test your application by turning on accessibility services like TalkBack and Explore by Touch, and try using your application using only directional controls.
Developers who create custom controls that extend from the View
class have
some additional responsibilities for making sure their components are accessible for users. This
document also discusses how to make custom view controls compatible with accessibility services.
Labeling User Interface Elements
Many user interface controls rely on visual cues to inform users of their meaning. For
example, a note-taking application might use an ImageButton
with a
picture of a plus sign to indicate that the user can add a new note. Or, an EditText
component may have a label near it that indicates its purpose. When a user
with impaired vision accesses your application, these visual cues are often useless.
To provide textual information about interface controls (as an alternative to the visual cues),
use the
android:contentDescription
attribute. The text you provide in this attribute is not
visible on the screen, but if a user has enabled accessibility services that provide audible
prompts, then the description in this attribute is read aloud to the user.
Set the
android:contentDescription
attribute for every ImageButton
,
ImageView
, EditText
, CheckBox
in your application's user interface, and on any other input controls that might require additional
information for users who are not able to see it.
For example, the following ImageButton
sets the content description for
the plus button to the add_note
string resource, which could be defined as “Add note" for an
English language interface:
<ImageButton android:id=”@+id/add_note_button” android:src=”@drawable/add_note” android:contentDescription=”@string/add_note”/>
By including the description, speech-based accessibility services can announce "Add note" when a user moves focus to this button or hovers over it.
Note: For EditText
fields, provide an
android:hint
attribute to help users understand what content is expected.
Enabling Focus Navigation
Focus navigation allows users with disabilities to step through user interface controls using a directional controller. Directional controllers can be physical, such as a clickable trackball, directional pad (D-pad) or arrow keys, tab key navigation with an attached keyboard or a software application, such as the Eyes-Free Keyboard, that provides an on-screen directional control.
A directional controller is a primary means of navigation for many users. Verify that all user interface (UI) controls in your application are accessible without using the touchscreen and that clicking with the center button (or OK button) of a directional controller has the same effect as touching the controls on the touchscreen. For information on testing directional controls, see Testing focus navigation.
Enabling view focus
A user interface element is accessible using directional controls when its
android:focusable
attribute is set to 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.
Android provides several APIs that let you control whether a user interface control is focusable and even request that a control be given focus:
When working with a view that is not focusable by default, you can make it focusable from the XML
layout file by setting the
android:focusable
attribute to true
or by using the setFocusable()
method.
Controlling focus order
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 ordering. The ordering of the focus movement is based on an algorithm that finds the nearest neighbor in a given direction. In rare cases, the default algorithm may not match the order that you intended for your UI. In these situations, you can provide explicit overrides to the ordering using the following XML attributes in the layout file:
android:nextFocusDown
- Defines the next view to receive focus when the user navigates down.
- 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.
android:nextFocusLeft
The following example XML layout shows two focusable user interface elements where the android:nextFocusDown
and android:nextFocusUp
attributes have been explicitly set. The TextView
is
located to the right of the EditText
. However, since these properties have
been set, the TextView
element can now be reached by pressing the down arrow
when focus is on the EditText
element:
<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>
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).
Note: You can modify the focus order of user interface components
at runtime, using methods such as setNextFocusDownId()
and setNextFocusRightId()
.
Building Accessible Custom Views
If your application requires a custom view component, 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:
- Handle directional controller clicks
- Implement Accessibility API methods
- Send
AccessibilityEvent
objects specific to your custom view - Populate
AccessibilityEvent
andAccessibilityNodeInfo
for your view
Handling directional controller clicks
On most devices, clicking a view using a directional controller sends a KeyEvent
with KEYCODE_DPAD_CENTER
to the view currently
in focus. All standard Android views already handle KEYCODE_DPAD_CENTER
appropriately. When building a custom View
control, make sure this event has the same effect as touching the view on the
touchscreen.
Your custom control should also treat the KEYCODE_ENTER
event the
same as KEYCODE_DPAD_CENTER
. This approach makes interaction from a
full keyboard much easier for users.
Implementing accessibility API methods
Accessibility events are messages about users interaction with visual interface components in
your application. These messages are handled by Accessibility Services,
which use the information in these events to produce supplemental feedback and prompts when users
have enabled accessibility services. As of Android 4.0 (API Level 14) and higher, the methods for
generating accessibility events have been expanded to provide more detailed information beyond the
AccessibilityEventSource
interface introduced in Android 1.6 (API
Level 4). The expanded accessibility methods are part of the View
class as well
as the View.AccessibilityDelegate
class. The methods are as follows:
sendAccessibilityEvent()
- (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
TYPE_VIEW_CLICKED
. You typically do not need to implement this method unless you are creating a custom view. sendAccessibilityEventUnchecked()
- (API Level 4) This method is used when the calling code needs to directly control the check
for accessibility being enabled on the device (
AccessibilityManager.isEnabled()
). If you do implement this method, you must assume that the calling method has already checked that accessibility is enabled and the result istrue
. You typically do not need to implement this method for a custom view. dispatchPopulateAccessibilityEvent()
- (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
onPopulateAccessibilityEvent()
for this view and then thedispatchPopulateAccessibilityEvent()
method for each child of this view. In order to support accessibility services on revisions of Android prior to 4.0 (API Level 14) you must override this method and populategetText()
with descriptive text for your custom view. onPopulateAccessibilityEvent()
- (API Level 14) This method sets the text output of an
AccessibilityEvent
for your view. This method is also called if the view is a child of a view which generates an accessibility event.Note: Modifying additional attributes beyond the text within this method potentially overwrites properties set by other methods. So, while you are able modify attributes of the accessibility event with this method, you should limit these changes to text content only and use the
onInitializeAccessibilityEvent()
method to modify other properties of the event.Note: If your implementation of this event calls for completely overiding 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.
onInitializeAccessibilityEvent()
- (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
TextView
orButton
, 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. onInitializeAccessibilityNodeInfo()
- (API Level 14) This method provides accessibility services with information about the state of
the view. The default
View
implementation sets a standard set of view properties, but if your custom view provides interactive control beyond a simpleTextView
orButton
, you should override this method and set the additional information about your view into theAccessibilityNodeInfo
object handled by this method. onRequestSendAccessibilityEvent()
- (API Level 14) The system calls this method when a child of your view has generated an
AccessibilityEvent
. This step allows the 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.
In order to support these accessibility methods for a custom view, you should take one of the following approaches:
- 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.
- If your custom view is intended to be compatible with Android 1.6 (API Level 4) and above, add
the Android Support Library, revision 5 or
higher, to your project. Then, within your custom view class, call the
ViewCompat.setAccessibilityDelegate()
method to implement the accessibility methods above. For an example of this approach, see the Android Support Library (revision 5 or higher) sampleAccessibilityDelegateSupportActivity
in (<sdk>/extras/android/support/v4/samples/Support4Demos/
)
In either case, you should implement the following accessibility methods for your custom view class:
dispatchPopulateAccessibilityEvent()
onPopulateAccessibilityEvent()
onInitializeAccessibilityEvent()
onInitializeAccessibilityNodeInfo()
For more information about implementing these methods, see Populating Accessibility Events.
Sending accessibility events
Depending on the specifics of your custom view, it may need to send AccessibilityEvent
objects at a different times or for events not
handled by the default implementation. The View
class provides a default
implementation for these event types:
- Starting with API Level 4:
- Starting with API Level 14:
Note: Hover events are associated with the Explore by Touch feature, which uses these events as triggers for providing audible prompts for user interface elements.
In general, you should send an 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 TYPE_VIEW_TEXT_CHANGED
whenever the slider
value changes. The following sample code demonstrates the use of the sendAccessibilityEvent()
method to report this event.
@Override public boolean onKeyUp (int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) { mCurrentValue--; sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED); return true; } ... }
Populating accessibility events
Each 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 AccessibilityEvent
reference documentation.
The 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.
The minimum requirement for providing information to accessibility services with a custom
view is to implement dispatchPopulateAccessibilityEvent()
. This method is called by the system to request
information for an 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.
@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); } }
On Android 4.0 (API Level 14) and higher, the onPopulateAccessibilityEvent()
and
onInitializeAccessibilityEvent()
methods are the recommended way to populate or modify the information in an AccessibilityEvent
. Use the
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
onInitializeAccessibilityEvent()
method for
populating additional information about the event, such as the selection state of the view.
In addition, you should also implement the
onInitializeAccessibilityNodeInfo()
method. 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.
The example code below shows how override these three methods by using
ViewCompat.setAccessibilityDelegate()
. Note that this sample code requires that the Android
Support Library for API Level 4 (revision 5
or higher) is added to your project.
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); } } }
On applications targeting Android 4.0 (API Level 14) and higher, these methods can be implemented
directly in your custom view class. For another example of this approach, see the Android
Support Library (revision 5 or higher) sample
AccessibilityDelegateSupportActivity
in
(<sdk>/extras/android/support/v4/samples/Support4Demos/
).
Note: You may find information on implementing accessibility for
custom views written prior to Android 4.0 that describes the use of the
dispatchPopulateAccessibilityEvent()
method for populating AccessibilityEvents. As of the Android 4.0 release, however, the recommended
approach is to use the
onPopulateAccessibilityEvent()
and
onInitializeAccessibilityEvent()
methods.
Testing Accessibility
Testing the accessibility of your application is an important part of ensuring your users have a great experience. You can test the most important parts of accessibility by testing your application with audible feedback enabled and testing navigation within your application using directional controls.
Testing audible feedback
You can simulate the experience for many users by enabling an accessibility service that speaks as you move around the screen. The Explore by Touch accessibility service, which is available on devices with Android 4.0 and later. The TalkBack accessibility service, by the Eyes-Free Project comes preinstalled on many Android devices.
To enable TalkBack on revisions of Android prior to Android 4.0:
- Launch the Settings application.
- Navigate to the Accessibility category and select it.
- Select Accessibility to enable it.
- Select TalkBack to enable it.
Note: If the TalkBack accessibility service is not available, you can install it for free from Google Play.
To enable Explore by Touch on Android 4.0 and later:
- Launch the Settings application.
- Navigate to the Accessibility category and select it.
- Select the TalkBack to enable it.
- Return to the Accessibility category and select Explore by
Touch to enable it.
Note: You must turn on TalkBack first, otherwise this option is not available.
Testing focus navigation
As part of your accessibility testing, you can test navigation of your application using focus, even if your test devices does not have a directional controller. The Android Emulator provides a simulated directional controller that you can easily use to test navigation. You can also use a software-based directional controller, such as the one provided by the Eyes-Free Keyboard to simulate use of a D-pad.