1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
|
page.title=Designing for Accessibility
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>Quickview</h2>
<ul>
<li>To make your application more accessible, you should make sure your UI is navigable
using a directional controller and your widgets provide content descriptions</li>
<li>If you implement a custom view, you should ensure that it delivers the appropriate
accessibility events during user interaction</li>
</ul>
<h2>In this document</h2>
<ol>
<li><a href="#Navigation">Allow Navigation with a Directional Controller</a>
<ol>
<li><a href="#FocusOrder">Controlling focus order</a></li>
<li><a href="#ClickingDpad">Clicking with a directional controller</a></li>
</ol>
</li>
<li><a href="#LabelInputs">Label Your Input Widgets</a></li>
<li><a href="#UiBestPractices">Follow Android UI Best Practices</a></li>
<li><a href="#CustomViews">Send Accessibility Events from Custom View Components</a></li>
<li><a href="#Test">Test Your Application’s Accessibility</a></li>
</ol>
<h2>Key classes</h2>
<ol>
<li>{@link android.view.accessibility.AccessibilityEvent}</li>
<li>{@link android.view.accessibility.AccessibilityEventSource}</li>
</ol>
<h2>Related samples</h2>
<ol>
<li><a
href="{@docRoot}resources/samples/AccessibilityService/index.html">Accessibility Service</a></li>
</ol>
</div>
</div>
<p>Many Android users have disabilities that require them to interact with their Android devices in
different ways. These include users who have visual, physical or age-related disabilities that
prevent them from fully using or seeing a touchscreen.</p>
<p>Android provides an accessibility layer that helps these users navigate their Android-powered
devices more easily. Android's accessibility services provide things like text-to-speech, haptic
feedback, and trackball/d-pad navigation that augment the user experience.</p>
<p>Your application should follow the guidelines in this document to ensure that it provides a
good experience for users with disabilities. Following these two basic rules will solve most
access-related problems:</p>
<ul>
<li>Make all of your user interface controls accessible with a trackball or directional
controller (d-pad).</li>
<li>Label your {@link android.widget.ImageButton}, {@link android.widget.EditText}, and other input
widgets using the <a
href="{@docRoot}reference/android/view/View.html#attr_android:contentDescription">{@code
android:contentDescription}</a> attribute.</li>
</ul>
<h2 id="Navigation">Allow Navigation with a Directional Controller</h2>
<p>Many Android devices come with some sort of directional controller, such as:</p>
<ul>
<li>A clickable trackball that users can move in any direction</li>
<li>A clickable d-pad that allows users to navigate in four directions.</li>
<li>Arrow keys and an OK button that’s equivalent to clicking a trackball or d-pad.</li>
</ul>
<p>All of these directional controllers allow users to navigate the screen without using the
touchscreen. On some devices, a user can also navigate to the top or bottom of a list by holding
down the <em>alt</em> key while pressing a discrete key for up or down.</p>
<p>A directional controller is the primary means of navigation for users with visual or some
physical impairments (and also for users without impairments when using devices that don't
have a touchscreen). You should verify that all UI controls in your application are
accessible without using the touchscreen and that clicking with the center button (or OK button) has
the same effect as touching the controls on the touchscreen.</p>
<p>A UI control (also called a "widget") is accessible using directional controls when it's
"focusable" property is "true." This means that users can focus on the widget using the directional
controls and then interact with it. Widgets provided by the Android APIs are focusable by default
and visually indicate focus by changing the widget visual appearance in some way.</p>
<p>Android provides several APIs that let you control whether a widget is focusable and even
request that a widget be given focus. Such methods include:</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>When working with a view that is not focusable by default, you can make it focusable from the XML
layout file by setting the <a
href="{@docRoot}reference/android/view/View.html#attr_android:focusable">{@code
android:focusable}</a> attribute to {@code "true"}.</p>
<h3 id="FocusOrder">Controlling focus order</h3>
<p>When the user navigates in any direction using the directional controls, focus is passed from one
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:</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>
<a><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>For example, here is an XML layout that contains a focusable {@link android.widget.TextView}.
While the {@link android.widget.TextView} is located to the right of the {@link
android.widget.EditText}, it can now be reached by pressing the down arrow when focus is on the
{@link android.widget.EditText}: </p>
<pre>
<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>
</pre>
<p>When modifying this ordering, be sure that the navigation works as expected in all directions
from each widget and when navigating in reverse (to get back to where you came from).</p>
<p>You can also modify the focus ordering at runtime, using methods in the {@link
android.view.View} class, such as {@link android.view.View#setNextFocusDownId
setNextFocusDownId()} and {@link android.view.View#setNextFocusRightId
setNextFocusRightId()}.</p>
<h3 id="ClickingDpad">Clicking with a directional controller</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. Make sure this event has the same effect as touching the view on the touchscreen. All
standard Android views already handle {@link android.view.KeyEvent#KEYCODE_DPAD_CENTER}
appropriately.</p>
<p>If possible, also treat the {@link android.view.KeyEvent#KEYCODE_ENTER} event the same as
{@link android.view.KeyEvent#KEYCODE_DPAD_CENTER}. That makes interaction much easier from a full
keyboard.</p>
<h2 id="LabelInputs">Label Your Input Widgets</h2>
<p>Many input widgets rely on visual cues to inform the user of their meaning. For example, a
notepad 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. Or, an {@link android.widget.EditText} may have
a label near it that indicates its purpose. When a visually impaired user accesses your
application, these visual cues are often useless.</p>
<p>To provide textual information about these widgets (as an alternative to the visual cues), you
should use the <a href="{@docRoot}reference/android/view/View.html#attr_android:contentDescription"
>{@code android:contentDescription}</a> attribute. The text you provide in this attribute
is not visible on the screen, but if a user has enabled accessibility speech tools then the
description in this attribute is read aloud to the user.</p>
<p>You should set the <a
href="{@docRoot}reference/android/view/View.html#attr_android:contentDescription" >{@code
android:contentDescription}</a> attribute on every {@link android.widget.ImageButton}, {@link
android.widget.EditText}, {@link android.widget.CheckBox}, and on any other input widgets that might
benefit users with extra information.</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 might be defined in English as
“Add note":</p>
<pre>
<ImageButton
android:id=”@+id/add_entry_button”
android:src=”@drawable/plus”
android:contentDescription=”@string/add_note”/>
</pre>
<p>This way, when using speech accessibility tools, the user hears "Add note" when focused on
this widget.</p>
<h2 id="UiBestPractices">Follow Android UI Best Practices</h2>
<p>You can make it easier for users to learn how to use your application by developing a user
interface that complies with Android's standard interaction patterns, instead of creating your own
or using interaction patterns from another platform. This consistency is especially important for
many disabled users, as they may have less contextual information available to try to understand
your application’s interface.</p>
<p>Specifically, you should:</p>
<ul>
<li>Use the platform's built-in widgets and layouts whenever possible, as these views provide
accessibility support by default.</li>
<li>Use the <a href="{@docRoot}guide/topics/ui/menus.html#options-menu">Options Menu</a> as an
alternative to complex touchscreen tasks.</li>
<li>Make sure the BACK button correctly moves the user back one logical step in the <a
href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">task's back stack</a> or the
activity's back stack of fragments (when <a
href="{@docRoot}guide/topics/fundamentals/fragments.html#Transactions">performing fragment
transactions</a>), as appropriate.</li>
</ul>
<h2 id="CustomViews">Send Accessibility Events from Custom View Components</h2>
<p>If your application requires that you create a <a
href="{@docRoot}guide/topics/ui/custom-components.html">custom view component</a>, you may need to
do some additional work to ensure that your view is accessible. Specifically, you should make sure
that your view implements the {@link android.view.accessibility.AccessibilityEventSource}
interface and emits {@link android.view.accessibility.AccessibilityEvent}s at the proper times,
and that each {@link android.view.accessibility.AccessibilityEvent} contains relevant information
about the state of the view.</p>
<p>Events are emitted whenever something notable happens in the user interface. Currently, there
are five types of accessibility events that a view should send to the system as the user interacts
with it:</p>
<dl>
<dt>{@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED}</dt>
<dd>Indicates that the user clicked on the view (for example, the user selects a button).</dd>
<dt>{@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_LONG_CLICKED}</dt>
<dd>Indicates that the user performed a long press on the view. </dd>
<dt>{@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SELECTED}</dt>
<dd>Indicates that the user selected an item from within the view. This is usually used in the
context of an {@link android.widget.AdapterView}.</dd>
<dt>{@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_FOCUSED}</dt>
<dd>Indicates that the user moved the focus to the view.</dd>
<dt>{@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED}</dt>
<dd>Indicates that the text or contents of the view changed.</dd>
</dl>
<p>The basic {@link android.view.View} class implements {@link
android.view.accessibility.AccessibilityEventSource} and emits these events at the proper time in
the standard cases. Your custom view should extend from {@link android.view.View} (or one of its
subclasses) to take advantage of these default implementations.</p>
<p>Depending on the specifics of your custom view, your view may need to emit one of these events at
a different time than the default {@link android.view.View} implementation. To do so, simply call
{@link android.view.accessibility.AccessibilityEventSource#sendAccessibilityEvent
sendAccessibilityEvent()} with the specific event type at the correct time.</p>
<p>For example, say you are implementing a custom slider bar that allows the user to select a
numeric value by pressing the left or right arrows. This view should emit an event of type {@link
android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED} whenever the slider value
changes:</p>
<pre>
@Override
public boolean onKeyUp (int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
mCurrentValue--;
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
return true;
}
...
}
</pre>
<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 like the view’s class name,
text and checked state. The specific properties required for each event type are described in the
{@link android.view.accessibility.AccessibilityEvent} documentation. The {@link android.view.View}
implementation will fill in default values for these properties. Most of these values, like the
class name and event timestamp, will not need to be changed. However, depending on the specifics of
your custom view, you may want to provide a different value for one or more of the properties. For
example, your view may have additional state information that you want to add to the event text.</p>
<p>The {@link android.view.View#dispatchPopulateAccessibilityEvent
dispatchPopulateAccessibilityEvent()} method in {@link android.view.View} provides a hook for making
changes to the {@link android.view.accessibility.AccessibilityEvent} object before it is
emitted.</p>
<p>In the above slider bar example, the view should add the current value of the slider bar to the
text of the event:</p>
<pre>
@Override
public boolean dispatchPopulateAccessibilityEvent(final AccessibilityEvent event) {
super.dispatchPopulateAccessibilityEvent(event);
if (!isShown()) {
return false;
}
CharSequence text = String.valueOf(mCurrentValue);
if (text.length() > AccessibilityEvent.MAX_TEXT_LENGTH) {
text = text.subSequence(0, AccessiblityEvent.MAX_TEXT_LENGTH);
}
event.getText().add(text);
return true;
}
</pre>
<h2 id="Test">Test Your Application’s Accessibility</h2>
<p>You can simulate the experience for many users by enabling an accessibility service that speaks
as you move around the screen. One such service is <a
href="https://market.android.com/details?id=com.google.android.marvin.talkback">TalkBack</a>, by the
<a href="http://code.google.com/p/eyes-free/">Eyes-Free Project</a>. It comes preinstalled on many
Android-powered devices, but is also available for free from <a
href="https://market.android.com/details?id=com.google.android.marvin.talkback">Android
Market</a>.</p>
<p>This service requires that you have a text-to-speech engine installed on your phone. You can
verify if you have one installed in the <strong>Text-to-speech</strong> settings menu by selecting
<strong>Listen to an example</strong>. If you do not hear anything spoken, install the required
voice data by selecting <strong>Install voice data</strong>.</p>
<p>Once text-to-speech is functioning correctly, you can enable TalkBack (or another accessibility
service) in the <strong>Accessibility</strong> settings menu. Enable both
<strong>Accessibility</strong> and <strong>TalkBack</strong>. As you navigate about the device, you
should now hear spoken feedback.</p>
<p>You can now attempt to use your application as a blind user would. As you move around using only
the directional controller, make sure that the spoken feedback you hear makes sense and is
sufficient to navigate the application without any visual cues.</p>
|