Requirements
Prerequisite knowledge

Some familiarity with Flex, MXML, and
ActionScript 3 is required. Knowledge of
the Cairngorm framework is helpful, but
not a necessity.
Required products

Adobe AIR
Flash Builder 4 (Download trial)
Sample files

User level

Intermediate

 

Requirements

Prerequisite knowledge

Some familiarity with Flex, MXML, and ActionScript 3 is required. Knowledge of the Cairngorm framework is helpful, but not a necessity.

User level

Intermediate

 
Additional Requirements

 
Flex 4 SDK
 
Freedom Scientific JAWS (demo) or Microsoft Narrator (included in Windows)
 
(optional) Cairngorm
 
Sample files:
Adobe AIR 2 introduces accessibility support, exposing the Flex framework and your own custom components to screen reader software. Now you can design your AIR application to be usable by users with vision-related disabilities. By leveraging this new feature in combination with existing layout and UI options, you can deliver AIR applications that are accessible to a wider audience, including visually impaired and blind users.
 
At the heart of this feature is built-in parity of AIR 2 with underlying Flex and Flash accessibility support. This means that you, as the developer, can make design decisions that lead to an accessible application, rather than an application that is largely impractical for individuals who rely on a screen reader such as JAWS from Freedom Scientific. I will explain these design decisions and show you how to make your application keyboard-navigable, use data binding to adjust the font size programmatically, and configure what text is read in modified Flex components.
 
Many of the examples I discuss are implemented in the sample application, Quoth the Twitter. You may want to download the sample files and follow along using your preferred IDE. Note that JAWS and Microsoft Narrator (a text-to-speech utility that comes with Windows) are only available on Microsoft Windows. If you are developing on Mac OS X or a flavor of Linux, I recommend testing your application using a screen reader within a virtualized instance of Windows XP running VMware.
 
Note: The sample code used in this article is also available as an open source application. You can access the latest version in the code repository on Google Code; you can also install the application from an AIR file directly.
 

 
Enabling accessibility in AIR 2 applications

The first step in creating an accessible AIR application is to enable accessibility support in AIR 2. This accessibility feature exposes existing accessibility-enabled components to desktop screen readers. When you enable it, Flex components that natively support accessibility (for example, Label, TextInput, or Button) will automatically expose their properties to the accessibility API. The same goes for the hooks that are provided by the underlying framework, accessed via the AccessibilityProperties class, which lets you control the presentation of Flash objects to accessibility aids.
 
 
Compiling with accessibility
To enable accessibility support, you must compile with accessibility. This is very simple in Flash Builder 4 beta:
 
  1. Right-click your project in the Package Explorer.
  2. Click Properties.
  3. In the Flex Compiler section, select Generate Accessible SWF File (see Figure 1).
  4. Click OK.
Select Generate Accessible SWF File as a compiler option.
Figure 1. Select Generate Accessible SWF File as a compiler option.
 
 
If you're compiling your project in another IDE or in the command line, you'll want to pass an additional argument to the AIR wrapper for the Flex compiler: --accessible or --compiler.accessible
 
For example, the command to compile the sample application for this tutorial would look like the following:
 
./amxmlc --accessible --library-path+=libs/ --source-path+=../as3preferenceslib/src,../as3corelib/src QuothTheTwitter.mxml
The paths will likely be different in your environment, and on Windows the command line arguments are specified with a single hyphen.
 
 
Supported components
With accessibility enabled, the next step is to design your application to take advantage of this new feature. Fortunately, this is straightforward, since Flex 3 provides 28 components that are compatible with the accessibility framework. Flex 4 components (also known as Spark components) will also have accessibility, but at the time of this writing it is not yet implemented. Refer to the Adobe Flex 3 help for a list of accessible Flex 3 components.
 
The sample application for this article uses many common components: Label, Button, TextInput, Accordion, List, and plenty of layout components, including HBox, VBox, and Spacer. All of these components are accessible without modification, even when the application changes states, enables or disables components, or plays effects.
 

 
Keyboard navigation and keyboard shortcuts

When designing or modifying your application for accessibility, try to imagine how a visually impaired user could navigate and understand its interface. Applications that lack keyboard support, use fixed font sizes, convey information using color alone, or feature adjacent items with very similar colors are more difficult for visually disabled users to use. These issues are not unique to AIR 2, but to make an accessible AIR application, you must incorporate solutions for addressing them into your design.
 
 
Keyboard navigation and tab order
The primary consideration for keyboard navigation is tab order. The tab order not only determines the sequence in which a user will interact with your application, but also how the screen reader will read your components (the reading order). Tab order is determined by the tabIndex property of every instance of the InteractiveObject class that is contained within the SWF file, and it's automatically set based on the order of these objects. As a result, Flash Player will often assign the indices in an order that appears incorrect to the user—especially because it doesn't take into account object hierarchies.
 
The solution is to set the tabIndex property manually on any InteractiveObjects that are not in the correct tab order. Resetting tab indices every time you modify your application’s user interface quickly becomes tedious, so I recommend setting them late in the design process. Additionally, you may want to skip indices to give yourself room to add components later on. If you want to avoid the problem of reordering indixes during development, you can use data binding as a temporary solution to map the numbers to the components. Using the MVC Cairngorm framework, such an arrangement might look like:
 
<mx:Button id="changeUsername" click="onClick(event)" tabIndex="{ModelLocator.getInstance().changeUsernameTabIndex}"/>
The reference to the changeUsernameTabIndex constant contained in your ModelLocator is the key: Flex will assign the correct value to the tabIndex property of your Button at run time, enabling you to maintain a series of tab indices in your ModelLocator. You can then remove the data binding at a later point in development, as you should avoid the overhead created by binding properties that will not change during application execution.
 
I did not use this approach in the sample application, but you might prefer having a central location to manage the indices in a larger project.
 
You can set the tabEnabled and focusEnabeld properties to false if you want to keep the Tab key from ever placing focus on a particular component. Note that this will not make the component unreadable by a screen reader.
 
 
Keyboard shortcuts
It is also helpful to give keyboard users shortcuts to common tasks. The shortcuts can be global or component-based. In the former case, you can simply specify a KeyDown event handler, and within it check to see if the user's input is a recognized shortcut. For example:
 
protected function titlewindow1_keyDownHandler(event:KeyboardEvent):void { if ( event.keyCode == Keyboard.ESCAPE ) { close(); } }
Simple shortcuts like this will streamline your application for all users.
 
Alternatively, you can have the operating system handle the shortcuts by creating a NativeMenu with NativeMenuItem. This is an easy way to create global shortcuts. To make the NativeMenu and NativeMenuItem keyboard accessible, you should set the mnemonicIndex property to specify the position of the mnemonic character in the menu item label, then set the keyEquivalent property to make the menu accessible via Control or Command key shortcuts also. The following example is adapted from the AIR application ShareFire:
 
if ( !NativeWindow.supportsMenu ) return; var nm:NativeMenu = new NativeMenu(); // _A_dd Feed Button -- the location of the mneomonic index var nmi:NativeMenuItem = new NativeMenuItem("Add Feed"); nmi.addEventListener(Event.SELECT, function(e:Event):void { // Button pressed. Open the Feed Drawer ModelLocator.getInstance().isFeedDrawerOpen = true; }); nmi.mnemonicIndex = 0; nmi.keyEquivalent = "a"; nm.addItem(nmi); … NativeApplication.nativeApplication.activeWindow.menu = nm;
When this code is executed, it creates a NativeMenu object, adds a NativeMenuItem object, and finally assigns this menu to the NativeWindow referenced by activeWindow. The user accesses the NativeMenuItem in one of two ways: either by navigating the menu via a key modifier (Alt in Windows) and the letter indicated by the mneomicIndex, or by pressing the letter key together with the key equivalent modifier (the Ctrl key on Windows or Linux and the Command key on Mac OS X). The letter assigned via the mnemonicIndex is indicated as an underlined character on Windows, and is ignored on operating systems that do not allow menu navigation using these indices. The keyEquivalent property, on the other hand, is a keyboard shortcut that is available on all operating systems.
 

 
Adjustable font sizes and high-contrast mode

Enabling the user to change the font sizes in your application improves readability and enhances ease of use, as does enabling the user to change the look and feel of your components. What one user may feel is an aesthetically pleasing, easy-to-read color scheme may be as difficult to read for a color-blind user as a small font size is to another. Thus, it is important that you build in functionality that enables the user to adjust font sizes and enhance the contrast and color of your components.
 
 
Adjustable font sizes
It’s easy to create an application with adjustable font sizes, and implementing such an application using an MVC framework such as Cairngorm is straightforward. The first step is to create variables to store the program's minimum, maximum, and current font sizes. In Cairngorm, these variables can go in the ModelLocator:
 
public const MIN_FONT_SIZE:uint = 10; public const MAX_FONT_SIZE:uint = 30; [Bindable] public var fontSize:uint;
The fontSize variable is Bindable, so event listeners will be called when it changes. The variables that define the minimum and maximum font sizes are constants.
 
Note: I define all of these variables as uint, because uint variables reportedly have slightly better performance than Number or int when used as loop iterators; it doesn't hurt to get into the habit of using them where you'll never have nonpositive values. (And when you do, int still performs better than Number.)
 
The second step is to make your application respond when the fontSize variable changes. This is done with data binding in one of the root-level components in your main application. The easiest and highest-level way to accomplish this is to bind the fontSize property of your mx:WindowedApplication component to the fontSize variable in the Model. The MXML inside the mx:WindowedApplication tag will look like this:
 
fontSize="{ModelLocator.getInstance().fontSize}"
The third step is to initialize this variable when your application starts up. This enables you to recall the previous value for the fontSize property. In the sample application, this is stored in the encrypted local store and accessed using the Preference object, a convenience class provided by the as3preferenceslib library. It is a good idea to keep all these initialization procedures in a central place. In Cairngorm, you can put them in an InitCommand object that implements the ICommand interface and executes this code:
 
ml:ModelLocator = ModelLocator.getInstance(); ml.fontSize = ml.prefs.getValue("fontSize",ml.MIN_FONT_SIZE);
This uses the prefs Preference object in the ModelLocator and checks for a value called fontSize. If this value is found, ml.fontSize is assigned to its value; otherwise, ml.fontSize is assigned to the MIN_FONT_SIZE constant that was defined earlier.
 
The final step is to allow users to change the fontSize variable in your application. You can use any of several controls for this, including a TextInput, DropDownList, or Slider. Any change to fontSize will automatically be reflected in the font size of your entire application. Creating a Slider with labels is a bit too lengthy to explain in this article, but you can refer to the fontSizeSlider HSlider component in Settings.mxml to see an example.
 
To recap, here are the four steps for creating an application with adjustable font sizes:
 
  1. Store the current font size in the Model.
  2. Bind the fontSize property in your WindowedApplication component to the fontSize variable.
  3. Restore and save the user's font size preference between sessions.
  4. Allow users to adjust the font size with an interactive component, such as a Slider control.
You can see these steps implemented in ModelLocator.as, QuothTheTwitter.mxml, InitCommand.as, and Settings.mxml respectively.
 
 
High-contrast mode
You can enhance the contrast of your components in AIR by programmatically loading or unloading CSS declarations for Flex 3 components, and by customizing Flex 4 components through Skin classes.
 
Note: Flex 4 still contains mx (also called Halo) components, but there are some differences in styling behavior that make some workarounds necessary. For example, a TextArea in Flex 3 can be styled with the backgroundColor property. In Flex 4, a TextArea using the Halo or Spark skin can only be styled by setting contentBackgroundColor or by changing its BorderSkin.
 
 
Styling your application with two styles in mind
The easiest way to adjust your entire application's visual appearance quickly is to design its appearance in a staged process. Follow this procedure to design your application's normal look and feel:
 
  1. Begin with mx:Style tags inside of your root component, or in the component you'll be styling first.
  2. Use CSS type selectors. Begin by styling broadly, and then refine your selections when you need more fine-grained control. For example, begin by styling all Button objects, then start defining individual styles, such as Button.loginButton.
  3. When the component is styled correctly, create a Normal.css style sheet and link your WindowedApplication component (or children components) to it with the source property of the mx:Style tag. Cut and paste all your mx:Style declarations into Normal.css.
    Once you've defined your Normal.css style sheet, you can make a high-contrast version:
     
  4. Make a copy of Normal.css and name it HighContrast.css
  5. Open HighContrast.css and edit the colors until you've styled the entire application.
Beginning with the normal style sheet tends to prevent duplication of work.
 
Quoth The Twitter supports a high-contrast mode.
Figure 2. Quoth The Twitter supports a high-contrast mode.
 
 
Changing the style sheets at run time
You can change styles at runtime using the StyleManager class.
 
When the user wants to load the HighContrast.css declarations, call:
 
StyleManager.loadStyleDeclarations("assets/HighContrast.swf",true);
To unload these declarations and revert to the Normal.css style sheet linked in your root component, use the following code:
 
StyleManager.unloadStyleDeclarations("assets/HighContrast.swf",true);
StyleManager will automatically refresh your AIR application to display the changes. Since styling your components is a normal part of application development, creating a high-contrast mode can be done with little additional effort. It is a valuable feature that will allow a wider audience to use your application.
 
For more component-specific implementation details, refer to HighContrast.css and Normal.css in the assets folder of the sample application.
 

 
Screen readers

The key feature in the AIR 2 accessibility framework is the ability for screen readers such as JAWS to attach to your application. Using JAWS, blind and visually impaired users can have the content of AIR applications read aloud. Here are some design considerations to keep in mind that will help your users make the most of this new feature:
 
  • Only Flex components that support accessibility will work without modification. There are currently 28 Flex 3 components that work with screen readers, and Flex 4 components will be upgraded to support it. Modifying or creating your own accessible components involves creating your own AccessibilityImplementations. For more information, watch the video, Building accessible Flex and Adobe AIR applications on Adobe TV.
  • Tab order determines the order in which the screen reader will read the application’s contents aloud. Make sure your tab indices are set appropriately. The screen reader software will begin with the components that have a tabIndex property, reading them in the order you specify. After reading these components, the screen reader will read any remaining components in the order they appear in the source code. The user can always interrupt this process.
 
Configuring what text is read
It is possible to override the text that AIR automatically exposes to the screen reader. For a custom component, you can control what is read by creating and assigning an AccessibilityProperties object. For example, the following code will set “Custom component” as the text to be read:
 
myComponent.accessibilityProperties = new AccessibilityProperties; myComponent.accessibilityProperties.name = "Custom component"; // other application logic ... Accessibility.updateProperties();
The call to updateProperties() will cause your application to be scanned for new or changed AccessibilityProperties objects; this call is needed after you create or make changes to any AccessibilityProperties objects. It is not necessary to call updateProperties() after every individual change; you should use it as you would a commit call, after you have made changes to all the AccessibilityProperties objects. It's a synchronous function that may take a few milliseconds to execute. If you call it unnecessarily, you will degrade performance.
 
 
Ensuring instructions are read
Form containers present instructions and controls visually in a way that is logical and familiar to the user. Screen readers use Form and FormItem containers to read content aloud in a similarly familiar and intuitive way. In AIR 2, your existing Form containers will work with screen readers without modification. Consider the following login form:
 
<mx:Form width="100%" height="100%"> <mx:FormHeading label="Enter your username and password."/> <mx:FormItem label="Username"> <mx:TextInput id="usernameTextInput" tabIndex="3"/> </mx:FormItem> <mx:FormItem label="Password"> <mx:TextInput id="passwordTextInput" displayAsPassword="true" tabIndex="4"/> </mx:FormItem> </mx:Form>
"Username" will be read aloud when the user tabs into the usernameTextInput, and "Password" will be read when the user tabs into the passwordTextInput. Note that the screen reader won't read the FormHeading text when the user tabs into the TextInput objects. The FormHeading text is exposed like a Label, however, and users can direct their screen readers to navigate to it.
 
As with other aspects of your program, you should take advantage of Flex containers such as Form and FormItem to expose your UI's structure to screen readers.
 
 
Detecting whether a screen reader is attached
In some cases, you may want to use a custom component when a screen reader is not in use, but fall back to accessible components when a screen reader is in use. Or, you may want to open a browser to display HTML when a screen reader is attached, but use the HTML component when one isn't.
 
It is easy to check whether a screen reader is attached. Here's an example keyDown handler from the sample application's List control:
 
protected function urlList_keyDownHandler(event:KeyboardEvent):void { if ( event.keyCode == Keyboard.ENTER ) { if ( Accessibility.active ) { // A screen reader is attached. Use the browser instead of the HTML component openURL(); } else { htmlView.location = urlList.selectedItem as String; // ... } } }
The Accessibility class doesn't provide any bindable values, so you can't use a Flex ChangeWatcher object or data binding. I find it helpful to create a Bindable variable in my Model that is assigned the value of Accessibility.active two seconds after my application has finished initializing. (The connection between the screen reader and AIR is not immediate, and, unfortunately, this results in a short period of time in which there is uncertainty as to the accuracy of the Accessibility.active property.) Although this variable doesn’t reflect the attachment or detachment of a screen reader after application initialization, the most typical use case (a visually impaired user starting my app with a screen reader already running) is covered.
 

 
Where to go from here

Making your AIR 2 application accessible is a multistep process, and the most important pieces are design considerations that you'll make throughout development. The key steps are:
 
  • Enable accessibility by passing the --accessible command line option to the Flex compiler, or by selecting the Generate Accessible SWF File compiler option.
  • Use components from the pool of 28 accessible Halo components, and use accessible Spark components as they become available.
  • Ensure a sensible tabIndex for every component. Set tabEnabled to false when you want to disable tab focus for a component.
  • Create global or component-based keyboard shortcuts. You can use the native menu for this.
  • Add features for people who have difficulty seeing the screen; allow the user to scale the font and change styles at run time. Use Flex data binding and store the variables in your Model. Use the encrypted local store to save the user's preferences.
  • If you need to, manually create and set accessibilityProperties.name to change the text that is read by the screen reader for your components.
  • Organize instructions and controls in Form and FormItem containers, rather than creating more complicated groups or container hierarchies. Screen readers will properly read the associated instructions or labels.
  • Wait two seconds before detecting if a screen reader is attached. Check Accessibility.active to determine if the user is using a screen reader.
Like all usability improvements, accessibility modifications can continue almost indefinitely. There are practical limits, of course, but I believe that the tips I've outlined in this article are both easy to implement and valuable to users. Encourage visually impaired users to try your programs and give you feedback to better understand areas that may need further improvement. (You may also want to attach a screen reader, turn your monitor off, and try using the application yourself without visual cues.)
 
You may then decide to modify existing components to add missing functionality. For example, I modified an HTML component to allow the user to navigate through the anchor tags using the arrow keys. For these sorts of modifications, it's essential that you have feedback from users who will actually be using these features. The modification and creation of new components is a complicated process; for more information, watch the Adobe MAX 2009 session, Building Accessible Flex and Adobe AIR Application