Merge "initial accessibility class commit" into ics-mr1
This commit is contained in:
committed by
Android (Google) Code Review
commit
95dc3b50fc
@@ -278,6 +278,23 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li class="toggle-list">
|
||||||
|
<div><a href="<?cs var:toroot ?>training/accessibility/index.html">
|
||||||
|
<span class="en">Implementing Accessibility</span>
|
||||||
|
</a> <span class="new">new!</span></div>
|
||||||
|
<ul>
|
||||||
|
<li><a href="<?cs var:toroot ?>training/accessibility/accessible-app.html">
|
||||||
|
<span class="en">Developing Accessible Applications</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li><a href="<?cs var:toroot ?>training/accessibility/service.html">
|
||||||
|
<span class="en">Developing Accessibility Services</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|||||||
194
docs/html/training/accessibility/accessible-app.jd
Normal file
194
docs/html/training/accessibility/accessible-app.jd
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
|
||||||
|
page.title=Developing Accessible Applications
|
||||||
|
parent.title=Implementing Accessibility
|
||||||
|
parent.link=index.html
|
||||||
|
|
||||||
|
trainingnavtop=true
|
||||||
|
next.title=Developing an Accessibility Service
|
||||||
|
next.link=service.html
|
||||||
|
|
||||||
|
@jd:body
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="tb-wrapper">
|
||||||
|
<div id="tb">
|
||||||
|
|
||||||
|
<h2>This lesson teaches you to</h2>
|
||||||
|
<ol>
|
||||||
|
<li><a href="#contentdesc">Add Content Descriptions</a></li>
|
||||||
|
<li><a href="#focus">Design for Focus Navigation</a></li>
|
||||||
|
<li><a href="#events">Fire Accessibility Events</a></li>
|
||||||
|
<li><a href="#testing">Test Your Application</a></li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<!-- other docs (NOT javadocs) -->
|
||||||
|
<h2>You should also read</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="{@docRoot}guide/topics/ui/accessibility/apps.html">Making
|
||||||
|
Applications Accessible</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>Android has several accessibility-focused features baked into the platform,
|
||||||
|
which make it easy to optimize your application for those with visual or
|
||||||
|
physical disabilities. However, it's not always obvious what the correct
|
||||||
|
optimizations are, or the easiest way to leverage the framework toward this
|
||||||
|
purpose. This lesson shows you how to implement the strategies and platform
|
||||||
|
features that make for a great accessibility-enabled Android application.</p>
|
||||||
|
|
||||||
|
<h2 id="contentdesc">Add Content Descriptions</h2>
|
||||||
|
<p>A well-designed user interface (UI) often has elements that don't require an explicit
|
||||||
|
label to indicate their purpose to the user. A checkbox next to an item in a
|
||||||
|
task list application has a fairly obvious purpose, as does a trash can in a file
|
||||||
|
manager application. However, to your users with vision impairment, other UI
|
||||||
|
cues are needed.</p>
|
||||||
|
|
||||||
|
<p>Fortunately, it's easy to add labels to UI elements in your application that
|
||||||
|
can be read out loud to your user by a speech-based accessibility service like <a
|
||||||
|
href="https://market.android.com/details?id=com.google.android.marvin.talkback">TalkBack</a>.
|
||||||
|
If you have a label that's likely not to change during the lifecycle of the
|
||||||
|
application (such as "Pause" or "Purchase"), you can add it via the XML layout,
|
||||||
|
by setting a UI element's <a
|
||||||
|
href="{@docRoot}reference/android/view.View#attr_android:contentDescription">android:contentDescription</a> attribute, like in this
|
||||||
|
example:</p>
|
||||||
|
<pre>
|
||||||
|
<Button
|
||||||
|
android:id=”@+id/pause_button”
|
||||||
|
android:src=”@drawable/pause”
|
||||||
|
android:contentDescription=”@string/pause”/>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>However, there are plenty of situations where it's desirable to base the content
|
||||||
|
description on some context, such as the state of a toggle button, or a piece
|
||||||
|
selectable data like a list item. To edit the content description at runtime,
|
||||||
|
use the {@link android.view.View#setContentDescription(CharSequence)
|
||||||
|
setContentDescription()} method, like this:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
String contentDescription = "Select " + strValues[position];
|
||||||
|
label.setContentDescription(contentDescription);
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>This addition to your code is the simplest accessibility improvement you can make to your
|
||||||
|
application, but one of the most useful. Try to add content descriptions
|
||||||
|
wherever there's useful information, but avoid the web-developer pitfall of
|
||||||
|
labelling <em>everything</em> with useless information. For instance, don't set
|
||||||
|
an application icon's content description to "app icon". That just increases
|
||||||
|
the noise a user needs to navigate in order to pull useful information from your
|
||||||
|
interface.</p>
|
||||||
|
|
||||||
|
<p>Try it out! Download <a
|
||||||
|
href="https://market.android.com/details?id=com.google.android.marvin.talkback">TalkBack</a>
|
||||||
|
(an accessibility service published by Google) and enable it in <strong>Settings
|
||||||
|
> Accessibility > TalkBack</strong>. Then navigate around your own
|
||||||
|
application and listen for the audible cues provided by TalkBack.</p>
|
||||||
|
|
||||||
|
<h2 id="focus">Design for Focus Navigation</h2>
|
||||||
|
<p>Your application should support more methods of navigation than the
|
||||||
|
touch screen alone. Many Android devices come with navigation hardware other
|
||||||
|
than the touchscreen, like a D-Pad, arrow keys, or a trackball. In addition,
|
||||||
|
later Android releases also support connecting external devices like keyboards
|
||||||
|
via USB or bluetooth.</p>
|
||||||
|
|
||||||
|
<p>In order to enable this form of navigation, all navigational elements that
|
||||||
|
the user should be able to navigate to need to be set as focusable. This
|
||||||
|
modification can be
|
||||||
|
done at runtime using the
|
||||||
|
{@link android.view.View#setFocusable View.setFocusable()} method on that UI
|
||||||
|
control, or by setting the <a
|
||||||
|
href="{@docRoot}android.view.View#attr_android:focusable">{@code
|
||||||
|
android:focusable}</a>
|
||||||
|
attrubute in your XML layout files.</p>
|
||||||
|
|
||||||
|
<p>Also, each UI control has 4 attributes,
|
||||||
|
<a href="{@docRoot}reference/android/view/View#attr_android:nextFocusUp">{@code
|
||||||
|
android:nextFocusUp}</a>,
|
||||||
|
<a
|
||||||
|
href="{@docRoot}reference/android/view/View#attr_android:nextFocusDown">{@code
|
||||||
|
android:nextFocusDown}</a>,
|
||||||
|
<a
|
||||||
|
href="{@docRoot}reference/android/view/View#attr_android:nextFocusLeft">{@code
|
||||||
|
android:nextFocusLeft}</a>,
|
||||||
|
and <a
|
||||||
|
href="{@docRoot}reference/android/view/View#attr_android:nextFocusRight">{@code
|
||||||
|
android:nextFocusRight}</a>,
|
||||||
|
which you can use to designate
|
||||||
|
the next view to receive focus when the user navigates in that direction. While
|
||||||
|
the platform determines navigation sequences automatically based on layout
|
||||||
|
proximity, you can use these attributes to override that sequence if it isn't
|
||||||
|
appropriate in your application. </p>
|
||||||
|
|
||||||
|
<p>For instance, here's how you represent a button and label, both
|
||||||
|
focusable, such that pressing down takes you from the button to the text view, and
|
||||||
|
pressing up would take you back to the button.</p>
|
||||||
|
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<Button android:id="@+id/doSomething"
|
||||||
|
android:focusable="true"
|
||||||
|
android:nextFocusDown=”@id/label”
|
||||||
|
... />
|
||||||
|
<TextView android:id="@+id/label"
|
||||||
|
android:focusable=”true”
|
||||||
|
android:text="@string/labelText"
|
||||||
|
android:nextFocusUp=”@id/doSomething”
|
||||||
|
... />
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>Verify that your application works intuitively in these situations. The
|
||||||
|
easiest way is to simply run your application in the Android emulator, and
|
||||||
|
navigate around the UI with the emulator's arrow keys, using the OK button as a
|
||||||
|
replacement for touch to select UI controls.</p>
|
||||||
|
|
||||||
|
<h2 id="events">Fire Accessibility Events</h2>
|
||||||
|
<p>If you're using the view components in the Android framework, an
|
||||||
|
{@link android.view.accessibility.AccessibilityEvent} is created whenever you
|
||||||
|
select an item or change focus in your UI. These events are examined by the
|
||||||
|
accessibility service, enabling it to provide features like text-to-speech to
|
||||||
|
the user.</p>
|
||||||
|
|
||||||
|
<p>If you write a custom view, make sure it fires events at the appropriate
|
||||||
|
times. Generate events by calling {@link
|
||||||
|
android.view.View#sendAccessibilityEvent(int)}, with a parameter representing
|
||||||
|
the type of event that occurred. A complete list of the event types currently
|
||||||
|
supported can be found in the {@link
|
||||||
|
android.view.accessibility.AccessibilityEvent} reference documentation.
|
||||||
|
|
||||||
|
<p>As an example, if you want to extend an image view such that you can write
|
||||||
|
captions by typing on the keyboard when it has focus, it makes sense to fire an
|
||||||
|
{@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED}
|
||||||
|
event, even though that's not normally built into image views. The code to
|
||||||
|
generate that event would look like this:</p>
|
||||||
|
<pre>
|
||||||
|
public void onTextChanged(String before, String after) {
|
||||||
|
...
|
||||||
|
if (AccessibilityManager.getInstance(mContext).isEnabled()) {
|
||||||
|
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
|
||||||
|
}
|
||||||
|
...
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<h2 id="testing">Test Your Application</h2>
|
||||||
|
<p>Be sure to test the accessibility functionality as you add it to your
|
||||||
|
application. In order to test the content descriptions and Accessibility
|
||||||
|
events, install and enable an accessibility service. One option is <a
|
||||||
|
href="https://play.google.com/store/details?id=com.google.android.marvin.talkback">Talkback</a>,
|
||||||
|
a free, open source screen reader available on Google Play. With the service
|
||||||
|
enabled, test all the navigation flows through your application and listen to
|
||||||
|
the spoken feedback.</p>
|
||||||
|
|
||||||
|
<p>Also, attempt to navigate your application using a directional controller,
|
||||||
|
instead of the touch screen. You can use a physical device with a d-pad or
|
||||||
|
trackball if one is available. If not, use the Android emulator and it's
|
||||||
|
simulated keyboard controls.</p>
|
||||||
|
|
||||||
|
<p>Between the service providing feedback and the directional navigation through
|
||||||
|
your application, you should get a sense of what your application is like to
|
||||||
|
navigate without any visual cues. Fix problem areas as they appear, and you'll
|
||||||
|
end up with with a more accessible Android application.</p>
|
||||||
56
docs/html/training/accessibility/index.jd
Normal file
56
docs/html/training/accessibility/index.jd
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
page.title=Implementing Accessibility
|
||||||
|
|
||||||
|
trainingnavtop=true
|
||||||
|
startpage=true
|
||||||
|
next.title=Developing Accessible Applications
|
||||||
|
next.link=accessible-app.html
|
||||||
|
|
||||||
|
@jd:body
|
||||||
|
|
||||||
|
<div id="tb-wrapper">
|
||||||
|
<div id="tb">
|
||||||
|
|
||||||
|
<h2>Dependencies and prerequisites</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Android 2.0 (API Level 5) or higher</li>
|
||||||
|
Playback</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>You should also read</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>When it comes to reaching as wide a userbase as possible, it's important to
|
||||||
|
pay attention to accessibility in your Android application. Cues in your user
|
||||||
|
interface that may work for a majority of users, such as a visible change in
|
||||||
|
state when a button is pressed, can be less optimal if the user is visually
|
||||||
|
impaired.</p>
|
||||||
|
|
||||||
|
<p>This class shows you how to make the most of the accessibility features
|
||||||
|
built into the Android framework. It covers how to optimize your app for
|
||||||
|
accessibility, leveraging platform features like focus navigation and content
|
||||||
|
descriptions. It also covers how to build accessibility services, that can
|
||||||
|
facilitate user interaction with <strong>any</strong> Android application, not
|
||||||
|
just your own.</p>
|
||||||
|
|
||||||
|
<h2>Lessons</h2>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt><b><a href="accessible-app.html">Developing Accessible Applications</a></b></dt>
|
||||||
|
<dd>Learn to make your Android application accessible. Allow for easy
|
||||||
|
navigation with a keyboard or directional pad, set labels and fire events
|
||||||
|
that can be interpreted by an accessibility service to facilitate a smooth
|
||||||
|
user experience.</dd>
|
||||||
|
|
||||||
|
<dt><b><a href="service.html">Developing Accessibility Services</a></b></dt>
|
||||||
|
<dd>Develop an accessibility service that listens for accessibility events,
|
||||||
|
mines those events for information like event type and content descriptions,
|
||||||
|
and uses that information to communicate with the user. The example will
|
||||||
|
use a text-to-speech engine to speak to the user.</dd>
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
286
docs/html/training/accessibility/service.jd
Normal file
286
docs/html/training/accessibility/service.jd
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
|
||||||
|
page.title=Developing an Accessibility Service
|
||||||
|
parent.title=Implementing Accessibility
|
||||||
|
parent.link=index.html
|
||||||
|
|
||||||
|
trainingnavtop=true
|
||||||
|
previous.title=Developing Accessible Applications
|
||||||
|
previous.link=accessible-app.html
|
||||||
|
|
||||||
|
@jd:body
|
||||||
|
|
||||||
|
<div id="tb-wrapper">
|
||||||
|
<div id="tb">
|
||||||
|
|
||||||
|
<h2>This lesson teaches you to</h2>
|
||||||
|
<ol>
|
||||||
|
<li><a href="#create">Create Your Accessibility Service</a></li>
|
||||||
|
<li><a href="#configure">Configure Your Accessibility Service</a></li>
|
||||||
|
<li><a href="#events">Respond to AccessibilityEvents</a></li>
|
||||||
|
<li><a href="#query">Query the View Heirarchy for More Context</a></li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h2>You should also read</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="{@docRoot}guide/topics/ui/accessibility/services.html">Building
|
||||||
|
Accessibility Services</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<p>Accessibility services are a feature of the Android framework designed to
|
||||||
|
provide alternative navigation feedback to the user on behalf of applications
|
||||||
|
installed on Android devices. An accessibility service can communicate to the
|
||||||
|
user on the application's behalf, such as converting text to speech, or haptic
|
||||||
|
feedback when a user is hovering on an important area of the screen. This
|
||||||
|
lesson covers how to create an accessibility service, process information
|
||||||
|
received from the application, and report that information back to the
|
||||||
|
user.</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="create">Create Your Accessibility Service</h2>
|
||||||
|
<p>An accessibility service can be bundled with a normal application, or created
|
||||||
|
as a standalone Android project. The steps to creating the service are the same
|
||||||
|
in either situation. Within your project, create a class that extends {@link
|
||||||
|
android.accessibilityservice.AccessibilityService}.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
package com.example.android.apis.accessibility;
|
||||||
|
|
||||||
|
import android.accessibilityservice.AccessibilityService;
|
||||||
|
|
||||||
|
public class MyAccessibilityService extends AccessibilityService {
|
||||||
|
...
|
||||||
|
@Override
|
||||||
|
public void onAccessibilityEvent(AccessibilityEvent event) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInterrupt() {
|
||||||
|
}
|
||||||
|
|
||||||
|
...
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>Like any other service, you also declare it in the manifest file.
|
||||||
|
Remember to specify that it handles the {@code android.accessibilityservice} intent,
|
||||||
|
so that the service is called when applications fire an
|
||||||
|
{@link android.view.accessibility.AccessibilityEvent}.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<application ...>
|
||||||
|
...
|
||||||
|
<service android:name=".MyAccessibilityService">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.accessibilityservice.AccessibilityService" />
|
||||||
|
</intent-filter>
|
||||||
|
. . .
|
||||||
|
</service>
|
||||||
|
...
|
||||||
|
</application>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>If you created a new project for this service, and don't plan on having an
|
||||||
|
application, you can remove the starter Activity class (usually called MainActivity.java) from your source. Remember to
|
||||||
|
also remove the corresponding activity element from your manifest.</p>
|
||||||
|
|
||||||
|
<h2 id="configure">Configure Your Accessibility Service</h2>
|
||||||
|
<p>Setting the configuration variables for your accessibility service tells the
|
||||||
|
system how and when you want it to run. Which event types would you like to
|
||||||
|
respond to? Should the service be active for all applications, or only specific
|
||||||
|
package names? What different feedback types does it use?</p>
|
||||||
|
|
||||||
|
<p>You have two options for how to set these variables. The
|
||||||
|
backwards-compatible option is to set them in code, using {@link
|
||||||
|
android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}.
|
||||||
|
To do that, override the {@link
|
||||||
|
android.accessibilityservice.AccessibilityService#onServiceConnected()} method
|
||||||
|
and configure your service in there.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
@Override
|
||||||
|
public void onServiceConnected() {
|
||||||
|
// Set the type of events that this service wants to listen to. Others
|
||||||
|
// won't be passed to this service.
|
||||||
|
info.eventTypes = AccessibilityEvent.TYPE_VIEW_CLICKED |
|
||||||
|
AccessibilityEvent.TYPE_VIEW_FOCUSED;
|
||||||
|
|
||||||
|
// If you only want this service to work with specific applications, set their
|
||||||
|
// package names here. Otherwise, when the service is activated, it will listen
|
||||||
|
// to events from all applications.
|
||||||
|
info.packageNames = new String[]
|
||||||
|
{"com.example.android.myFirstApp", "com.example.android.mySecondApp"};
|
||||||
|
|
||||||
|
// Set the type of feedback your service will provide.
|
||||||
|
info.feedbackType = AccessibilityServiceInfo.FEEDBACK_SPOKEN;
|
||||||
|
|
||||||
|
// Default services are invoked only if no package-specific ones are present
|
||||||
|
// for the type of AccessibilityEvent generated. This service *is*
|
||||||
|
// application-specific, so the flag isn't necessary. If this was a
|
||||||
|
// general-purpose service, it would be worth considering setting the
|
||||||
|
// DEFAULT flag.
|
||||||
|
|
||||||
|
// info.flags = AccessibilityServiceInfo.DEFAULT;
|
||||||
|
|
||||||
|
info.notificationTimeout = 100;
|
||||||
|
|
||||||
|
this.setServiceInfo(info);
|
||||||
|
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>Starting with Android 4.0, there is a second option available: configure the
|
||||||
|
service using an XML file. Certain configuration options like
|
||||||
|
{@link android.R.attr#canRetrieveWindowContent} are only available if you
|
||||||
|
configure your service using XML. The same configuration options above, defined
|
||||||
|
using XML, would look like this:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<accessibility-service
|
||||||
|
android:accessibilityEventTypes="typeViewClicked|typeViewFocused"
|
||||||
|
android:packageNames="com.example.android.myFirstApp, com.example.android.mySecondApp"
|
||||||
|
android:accessibilityFeedbackType="feedbackSpoken"
|
||||||
|
android:notificationTimeout="100"
|
||||||
|
android:settingsActivity="com.example.android.apis.accessibility.TestBackActivity"
|
||||||
|
android:canRetrieveWindowContent="true"
|
||||||
|
/>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>If you go the XML route, be sure to reference it in your manifest, by adding
|
||||||
|
a <a
|
||||||
|
href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data></a> tag to
|
||||||
|
your service declaration, pointing at the XML file. If you stored your XML file
|
||||||
|
in {@code res/xml/serviceconfig.xml}, the new tag would look like this:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<service android:name=".MyAccessibilityService">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.accessibilityservice.AccessibilityService" />
|
||||||
|
</intent-filter>
|
||||||
|
<meta-data android:name="android.accessibilityservice"
|
||||||
|
android:resource="@xml/serviceconfig" />
|
||||||
|
</service>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<h2 id="events">Respond to AccessibilityEvents</h2>
|
||||||
|
<p>Now that your service is set up to run and listen for events, write some code
|
||||||
|
so it knows what to do when an {@link
|
||||||
|
android.view.accessibility.AccessibilityEvent} actually arrives! Start by
|
||||||
|
overriding the {@link
|
||||||
|
android.accessibilityservice.AccessibilityService#onAccessibilityEvent} method.
|
||||||
|
In that method, use {@link
|
||||||
|
android.view.accessibility.AccessibilityEvent#getEventType} to determine the
|
||||||
|
type of event, and {@link
|
||||||
|
android.view.accessibility.AccessibilityEvent#getContentDescription} to extract
|
||||||
|
any label text associated with the fiew that fired the event.</pre>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
@Override
|
||||||
|
public void onAccessibilityEvent(AccessibilityEvent event) {
|
||||||
|
final int eventType = event.getEventType();
|
||||||
|
String eventText = null;
|
||||||
|
switch(eventType) {
|
||||||
|
case AccessibilityEvent.TYPE_VIEW_CLICKED:
|
||||||
|
eventText = "Focused: ";
|
||||||
|
break;
|
||||||
|
case AccessibilityEvent.TYPE_VIEW_FOCUSED:
|
||||||
|
eventText = "Focused: ";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
eventText = eventText + event.getContentDescription();
|
||||||
|
|
||||||
|
// Do something nifty with this text, like speak the composed string
|
||||||
|
// back to the user.
|
||||||
|
speakToUser(eventText);
|
||||||
|
...
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<h2 id="query">Query the View Heirarchy for More Context</h2>
|
||||||
|
<p>This step is optional, but highly useful. One of the new features in Android
|
||||||
|
4.0 (API Level 14) is the ability for an
|
||||||
|
{@link android.accessibilityservice.AccessibilityService} to query the view
|
||||||
|
hierarchy, collecting information about the the UI component that generated an event, and
|
||||||
|
its parent and children. In order to do this, make sure that you set the
|
||||||
|
following line in your XML configuration:</p>
|
||||||
|
<pre>
|
||||||
|
android:canRetrieveWindowContent="true"
|
||||||
|
</pre>
|
||||||
|
<p>Once that's done, get an {@link
|
||||||
|
android.view.accessibility.AccessibilityNodeInfo} object using {@link
|
||||||
|
android.view.accessibility.AccessibilityEvent#getSource}. This call only
|
||||||
|
returns an object if the window where the event originated is still the active
|
||||||
|
window. If not, it will return null, so <em>behave accordingly</em>. The
|
||||||
|
following example is a snippet of code that, when it receives an event, does
|
||||||
|
the following:
|
||||||
|
<ol>
|
||||||
|
<li>Immediately grab the parent of the view where the event originated</li>
|
||||||
|
<li>In that view, look for a label and a check box as children views</li>
|
||||||
|
<li>If it finds them, create a string to report to the user, indicating
|
||||||
|
the label and whether it was checked or not.</li>
|
||||||
|
<li>If at any point a null value is returned while traversing the view
|
||||||
|
hierarchy, the method quietly gives up.</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
|
||||||
|
// Alternative onAccessibilityEvent, that uses AccessibilityNodeInfo
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAccessibilityEvent(AccessibilityEvent event) {
|
||||||
|
|
||||||
|
AccessibilityNodeInfo source = event.getSource();
|
||||||
|
if (source == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab the parent of the view that fired the event.
|
||||||
|
AccessibilityNodeInfo rowNode = getListItemNodeInfo(source);
|
||||||
|
if (rowNode == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Using this parent, get references to both child nodes, the label and the checkbox.
|
||||||
|
AccessibilityNodeInfo labelNode = rowNode.getChild(0);
|
||||||
|
if (labelNode == null) {
|
||||||
|
rowNode.recycle();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AccessibilityNodeInfo completeNode = rowNode.getChild(1);
|
||||||
|
if (completeNode == null) {
|
||||||
|
rowNode.recycle();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine what the task is and whether or not it's complete, based on
|
||||||
|
// the text inside the label, and the state of the check-box.
|
||||||
|
if (rowNode.getChildCount() < 2 || !rowNode.getChild(1).isCheckable()) {
|
||||||
|
rowNode.recycle();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CharSequence taskLabel = labelNode.getText();
|
||||||
|
final boolean isComplete = completeNode.isChecked();
|
||||||
|
String completeStr = null;
|
||||||
|
|
||||||
|
if (isComplete) {
|
||||||
|
completeStr = getString(R.string.checked);
|
||||||
|
} else {
|
||||||
|
completeStr = getString(R.string.not_checked);
|
||||||
|
}
|
||||||
|
String reportStr = taskLabel + completeStr;
|
||||||
|
speakToUser(reportStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>Now you have a complete, functioning accessibility service. Try configuring
|
||||||
|
how it interacts with the user, by adding Android's <a
|
||||||
|
href="http://developer.android.com/resources/articles/tts.html">text-to-speech
|
||||||
|
engine</a>, or using a {@link android.os.Vibrator} to provide haptic
|
||||||
|
feedback!</p>
|
||||||
Reference in New Issue
Block a user