Loading docs/html/resources/resources_toc.cs +17 −0 Original line number Diff line number Diff line Loading @@ -278,6 +278,23 @@ </li> </ul> </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> </li> Loading docs/html/training/accessibility/accessible-app.jd 0 → 100644 +194 −0 Original line number Diff line number Diff line 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> docs/html/training/accessibility/index.jd 0 → 100644 +56 −0 Original line number Diff line number Diff line 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> docs/html/training/accessibility/service.jd 0 → 100644 +286 −0 Original line number Diff line number Diff line 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> Loading
docs/html/resources/resources_toc.cs +17 −0 Original line number Diff line number Diff line Loading @@ -278,6 +278,23 @@ </li> </ul> </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> </li> Loading
docs/html/training/accessibility/accessible-app.jd 0 → 100644 +194 −0 Original line number Diff line number Diff line 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>
docs/html/training/accessibility/index.jd 0 → 100644 +56 −0 Original line number Diff line number Diff line 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>
docs/html/training/accessibility/service.jd 0 → 100644 +286 −0 Original line number Diff line number Diff line 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>