Monday, November 3, 2008

RIA Accessibility with Flex

The blog entry Accessibility in Adobe Flex was recently featured on DZone and reminded me of another question I was asked by an attendee of one of my three presentations of Applying Flash to Java: Flex and OpenLaszlo at Colorado Software Summit 2008. The conference attendee wanted to know what type of accessibility support Flex offers. In this blog entry, I will reference several good overviews on Flex accessibility (and Flash accessibility) and then demonstrate a couple aspects of Flex accessibility support with concrete code examples.

Nick Boldison's blog entry Accessibility in Adobe Flex provides a brief introduction to and overview of accessibility issues with a Flex perspective. Adobe provides a Flex Accessibility Overview and Flash Accessibility Overview that also provide good high-level descriptions of what Flex and Flash respectively can do for increased accessibility.

The Flex Accessibility Overview explains that Flex comes with 28 components that include built-in accessibility support.

Another useful document related to Flex and accessibility issues is the Accessibility Best Practices for Flex document, which reminds the reader of the importance of testing Flex-based applications and also suggests that the developer of highly accessible Flex applications understand the basics of different types of limited access and how to overcome those types of limited access. In an effort to help with this, this document describes the preferred means of access for individuals with blindness, with vision impairment, with color blindness, with hardness of hearing, and with mobility impairment.

The Accessibility Best Practices for Flex document also explains how to turn Flex's built-in accessibility on (probably not on by default because of the "small but nontrivial increase in the size" of the generated .swf file). In short, the four main approaches (with greater detail shown in the Best Practices document) for turning on accessibility in Flex 3 applications are: (1) globally via the flex-config.xml file, (2) per application using the Flex 3 command-line compiler (mxmlc and its -accessible option), (3) using FlexBuilder 3's compiler option for accessible applications in project properties, and (4) at runtime by adding the appropriate query parameter.

Before moving onto some concrete examples of ensuring greater accessibility in Flex applications, I want to reference a couple more useful resources. These include the Flex Accessibility FAQ (includes a list of the 28 components with built-in accessibility support), Accessibility and Flex: We Can Do Better, Adobe Needs to Improve Accessibility in Flash Player, and the Adobe Flex 3 Help section Creating Accessible Applications.


Tab Order

The Flex 3 Help article Creating Tab Order and Reading Order talks about using the Tab key and specific ordering of elements via the Tab button to help improve a Flex application's accessibility. It is very easy in Flex to explicitly take advantage of tab order support using the tabIndex attribute. Flash applications do have a default (automatic) tab order that is overridden if at least one Flex component has tabIndex explicitly specified. Tab ordering will be demonstrated in the example at the end of this blog entry.


Detecting a Screen Reader

There is a Flash class called flash.accessibility.Accessibility that provides an active property that allows Flex code to detect whether a screen reader is being used. This allows the Flex application to present different things depending on the presence or absence of a screen reader. This will also be demonstrated in the example at the end of this blog entry.


Colors

I had a manager on my first real Flex application who constantly wanted to tweak the colors of the application because of issues that made it difficult for him to see the effects and contrasts due to his color blindness. I learned then the value of making it easy to change color settings. I have liked the ColorPicker component since then for making it really easy for the user to select preferred colors.


Tool Tips

The example at the end of this blog entry includes Tool Tips on the form items as well as on the rendered chart. Tool Tips are especially useful when the graphic or image does not contain any text and the tool tip can describe what the image shows.


The Example

With the above concepts described, it is time to move onto the example. This single example demonstrates the above specific concepts. It also takes advantage of the Google Charts API as described in one of my previous blog entries to build the chart dynamically and to populate an associated Tool Tip for the chart. Besides demonstrating tool tips, it also demonstrates tab ordering, color selection, and detecting absence or presence of a screen reader. In addition to demonstrating some Flex accessibility features and the use of Google Charts API, this example also demonstrates use of E4X features of Flex and ActionScript 3.0.

Here is the code listing for AccessibilityExample.mxml:


<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
width="1150" height="700"
applicationComplete="initializeApp();">

<!-- Example of some of Flex's Accessibility Features for the blog
Dustin's Cogitations and Speculations. That blog is available at
http://marxsoftware.blogspot.com/.-->

<mx:XMLList id="departmentsInfo">
<data>
<department name="Accounting" totalEmployees="3"/>
<department name="Engineering" totalEmployees="25" />
<department name="Human Resources" totalEmployees="2" />
<department name="Management" totalEmployees="10" />
<department name="Sales" totalEmployees="15" />
<department name="Support" totalEmployees="50" />
</data>
</mx:XMLList>

<mx:Script>
<![CDATA[
import flash.accessibility.Accessibility;
import mx.controls.Alert;

/**
* Initialize this application by indicating whether or not a
* screen reader is being used and by generating a chart using
* Google Chart API.
*/
public function initializeApp():void
{
ascertainScreenReaderUse();
generateChart();
}

/**
* Determine whether a screen reader is being used and indicate
* any such use.
*/
private function ascertainScreenReaderUse():void
{
const screenReaderStatus:String = "A screen reader is ";
if ( Accessibility.active == true )
{
screenReaderIndicator.text = screenReaderStatus + "being used.";
}
else
{
screenReaderIndicator.text = screenReaderStatus + "not being used.";
}
}

/**
* Generate chart for display.
*/
private function generateChart():void
{
// Use Google Charts (http://code.google.com/apis/chart/basics.html)
// to build a 750x300 3D pie chart from the XML data for departments and
// employees and scaled to between zero and fifty employees per department.
const urlBase:String =
"http://chart.apis.google.com/chart?cht=p3&chs=750x300&chd=t:"
var urlDataVar:String = "";
var urlDataLabelsVar:String = "";
var toolTipVarStr:String = "Distribution of Employees by Department: ";
for each (var department:XML in departmentsInfo.department)
{
urlDataVar += department.@totalEmployees;
urlDataVar += ",";
const deptNameAndCount:String =
department.@name + " (" + department.@totalEmployees + ")";
urlDataLabelsVar += deptNameAndCount + "|";

toolTipVarStr += deptNameAndCount;
toolTipVarStr += ", ";
}
chart.toolTip = toolTipVarStr;
const urlDataVarSize:uint = urlDataVar.length;
const urlData:String = urlDataVar.substr(0, urlDataVarSize-1);
const urlDataLabelsVarSize:uint = urlDataLabelsVar.length;
const urlLabelsStr:String = urlDataLabelsVar.substr(0, urlDataLabelsVarSize-1);
const urlLabels:String = "&chl=" + urlLabelsStr;
const urlScaling:String = "&chds=0,50";
const url:String = urlBase + urlData + urlLabels + urlScaling;
chart.source = url;
}
]]>
</mx:Script>

<mx:Panel id="mainPanel" title="Dustin's Accessibility with Flex Example"
layout="horizontal"
width="{application.width-10}"
height="{application.height-75}"
backgroundColor="{backgroundColorSelector.selectedColor}">
<mx:Form id="mainForm" width="{mainPanel.width*0.35}">
<mx:FormHeading label="Enter Personnel Information"
tabIndex="1" />
<mx:FormItem id="formItemName" label="Name" required="true"
tabIndex="2" toolTip="Name">
<mx:TextInput id="textInputItemName" tabIndex="3" />
</mx:FormItem>
<mx:FormItem id="formItemAddress1" label="Address" required="true"
tabIndex="4" toolTip="Address">
<mx:TextInput id="textInputAddress1" tabIndex="5" />
</mx:FormItem>
<mx:FormItem id="formItemAddress2" label="Address (cont)" required="false"
tabIndex="6" toolTip="Address (cont)">
<mx:TextInput id="textInputAddress2" tabIndex="7" />
</mx:FormItem>
<mx:FormItem id="formItemCity" label="City" required="true"
tabIndex="8" toolTip="City">
<mx:TextInput id="textInputCity" tabIndex="9" />
</mx:FormItem>
<mx:FormItem id="formItemState" label="State" required="true"
tabIndex="10" toolTip="State">
<mx:TextInput id="textInputState" tabIndex="11" />
</mx:FormItem>
<mx:FormItem id="formItemZip" label="Zip Code" required="true"
tabIndex="12" toolTip="Zip Code">
<mx:TextInput id="textInputZip" tabIndex="13" />
</mx:FormItem>
<mx:FormItem id="formItemFavoriteColor"
label="Favorite Color" required="false"
toolTip="Favorite Color">
<mx:RadioButtonGroup id="favoriteColorRadioGroup" />
<mx:RadioButton groupName="favoriteColorRadioGroup"
label="Blue"
tabIndex="14"
color="#000099" />
<mx:RadioButton groupName="favoriteColorRadioGroup"
label="Green"
tabIndex="15"
color="#00CC00" />
<mx:RadioButton groupName="favoriteColorRadioGroup"
label="Orange"
tabIndex="16"
color="#FF9900" />
<mx:RadioButton groupName="favoriteColorRadioGroup"
label="Red"
tabIndex="17"
color="#FF0000" />
<mx:RadioButton groupName="favoriteColorRadioGroup"
label="Yellow"
tabIndex="18"
color="#FFFF00" />
</mx:FormItem>
</mx:Form>
<mx:Panel id="secondaryPanel"
title="Administration Features"
backgroundColor="{backgroundColorSelector.selectedColor}"
width="{mainPanel.width*0.65}"
height="{mainPanel.height}">
<mx:Label id="backgroundColorSelectorLabel"
text="Select Background Color"
fontWeight="bold"
tabIndex="19" toolTip="Select Background Color" />
<mx:ColorPicker id="backgroundColorSelector" selectedColor="#CCCCCC"
tabIndex="20" toolTip="Select Background Color" />
<mx:Spacer height="15" />
<mx:Label text="Screen Reader Status" fontWeight="bold" />
<mx:Label id="screenReaderIndicator" />
<mx:Spacer height="25" />
<mx:Image id="chart" width="{secondaryPanel.width}" />
</mx:Panel>
</mx:Panel>

</mx:Application>




Some Issues/Limitations To Be Aware Of

There are a few caveats worth considering regarding Flex and Flash accessibility support. The Flash Player 10 Accessibility Overview points out that Internet Explorer is the required web browser for screen reader users. This same document also points out that screen reader users need a screen reader that includes a Flash Player implementation of Microsoft Active Accessibility (MSAA).

Other issues to be aware of include the need for screen reader users to download and run scripts provided here for using Flex with JAWS (a popular screen reader). For other issues to keep in mind when applying Flex to Rich Internet Applications with high accessibility, see Frustration with Accessibility in Flash and Flex, Adobe Needs to Improve Accessibility in Flash, Accessibility in Flash Bug and Issue List, Accessibility and Flex: We Can Do Better, and Flash and Accessibility.


Conclusion

This blog entry has only scratched the surface of Flex support for greater accessibility. While there are still some spots where Flex and Flash support for accessibility could be improved, it is encouraging to see the strides taken in making Flash more accessible and in allowing Flex to take advantage of these Flash improvements.

No comments: