Accessibility for Spark Components - Functional and Design Specification


Glossary


accessibility - The practice of making software usable by all people regardless of their abilities or disabilities. For Flex applications, a primary concern is whether they can be used by visually impaired users.

MSAA - Microsoft Active Accessibility, a specification by which MSAA client applications such as JAWS, a screen reader, communicate with MSAA server applications such as Flash Player.

IAccessible - A COM interface defined by MSAA so that MSAA clients can talk to MSAA servers.

ISimpleTextSelection - Another COM interface defined by Adobe to supplement IAccessible by providing information about text selection in components with editable text, since MSAA does not include this information.

accessibility implementation class - A subclass of flash.accessibility.AccessibilityImplementation which provides default MSAA behavior for a component.

accessibility properties - Information set into the flash.accessibility.AccessibilityProperties instance associated with a component, which customizes the default behavior of the accessibility implementation class for a particular component instance.

Summary and Background


Most of the MX components had long had corresponding accessibility implementation classes. In Flex 4 we will provide accessibility implementaton classes for the new Spark components.

We will make it easier to write such classes by documenting the new Spark accessibility implementation classes in detail, and by providing and documenting the MSAA constants used in such classes.

We will make it easier to set the accessibility properties for a component by adding accessibilityName and accessibilityDescription properties to UIComponent.

Finally, we will turn on accessibility by default, so that unless a Flex application is compiled with -accessible=false it will automatically provide MSAA information to screen readers, when executing on Flash runtimes supporting MSAA.

Usage Scenarios


Same as for MX components.

Detailed Description


New accessibility implementation classes

The following Spark components will be made accessible by writing a corresponding accessibility implementation class (e.g., spark.accessibility.ButtonAccImpl to go with spark.components.Button). The MSAA behavior provided by these classes is described in each link below.

Spark Component Accessibility Implementation Class
mx.accessibility.AccImpl mx.accessibility.AccImpl
spark.components.Button spark.accessibility.ButtonBaseAccImpl
spark.components.ButtonBar spark.accessibility.ButtonBarAccImpl
spark.components.CheckBox spark.accessibility.CheckBoxAccImpl
spark.components.ComboBox spark.accessibility.ComboBoxAccImpl
spark.components.DropDownList spark.accessibility.DropDownListAccImpl
spark.components.HSlider spark.accessibility.SliderAccImpl
spark.components.Label spark.accessibility.TextBaseAccImpl
spark.components.List spark.accessibility.ListBaseAccImpl
spark.components.NumericStepper spark.accessibility.NumericStepperAccImpl
spark.components.Panel spark.accessibility.PanelAccImpl
spark.components.RadioButton spark.accessibility.RadioButtonAccImpl
spark.components.RichEditableText spark.accessibility.RichEditableTextAccImpl
spark.components.RichText spark.accessibility.TextBaseAccImpl
spark.components.Spinner spark.accessibility.SpinnerAccImpl
spark.components.TabBar spark.accessibility.TabBarAccImpl
spark.components.TextArea spark.accessibility.TextAreaAccImpl
spark.components.TextInput spark.accessibility.TextInputAccImpl
spark.components.supportclasses.SkinnableTextBase spark.accessibility.SkinnableTextBaseAccImpl
spark.components.TitleWindow spark.accessibility.TitleWindowAccImpl
spark.components.ToggleButton spark.accessibility.ToggleButtonAccImpl
spark.components.VideoElement mx.accessibility.UIComponentAccImpl
spark.components.VideoPlayer spark.accessibility.VideoPlayerAccImpl
spark.components.VSlider spark.accessibility.SliderAccImpl
spark.components.Window spark.accessibility.WindowAccImpl
spark.components.WindowedApplication spark.accessibility.WindowedApplicationAccImpl

The Spark accessibility implementation classes, like the MX ones, will extend the existing mx.accessibility.AccImpl class, which itself extends flash.accessibility.AccessibilityImplementation. A description of AccImpl is here:

AccImpl

The Spark accessibility implementation classes will live in spark.swc in the spark.accessibility package.

MSAA constants

States

private static const STATE_SYSTEM_NORMAL:uint = 0x0;
private static const STATE_SYSTEM_UNAVAILABLE:uint = 0x00000001;
private static const STATE_SYSTEM_SELECTED:uint = 0x00000002;
private static const STATE_SYSTEM_FOCUSED:uint = 0x00000004;
private static const STATE_SYSTEM_PRESSED:uint = 0x00000008;
private static const STATE_SYSTEM_CHECKED:uint = 0x00000010;
private static const STATE_SYSTEM_MIXED:uint = 0x00000020;
private static const STATE_SYSTEM_INDETERMINATE:uint = 0x00000020;
private static const STATE_SYSTEM_READONLY:uint = 0x00000040;
private static const STATE_SYSTEM_HOTTRACKED:uint = 0x00000080;
private static const STATE_SYSTEM_DEFAULT:uint = 0x00000100;
private static const STATE_SYSTEM_EXPANDED:uint = 0x00000200;
private static const STATE_SYSTEM_COLLAPSED:uint = 0x00000400;
private static const STATE_SYSTEM_BUSY:uint = 0x00000800;
private static const STATE_SYSTEM_MARQUEED:uint = 0x00002000;
private static const STATE_SYSTEM_ANIMATED:uint = 0x00004000;
private static const STATE_SYSTEM_INVISIBLE:uint = 0x00008000;
private static const STATE_SYSTEM_OFFSCREEN:uint = 0x00010000;
private static const STATE_SYSTEM_SIZEABLE:uint = 0x00020000;
private static const STATE_SYSTEM_MOVEABLE:uint = 0x00040000;
private static const STATE_SYSTEM_SELFVOICING:uint = 0x00080000;
private static const STATE_SYSTEM_FOCUSABLE:uint = 0x00100000;
private static const STATE_SYSTEM_SELECTABLE:uint = 0x00200000;
private static const STATE_SYSTEM_LINKED:uint = 0x00400000;
private static const STATE_SYSTEM_TRAVERSED:uint = 0x00800000;
private static const STATE_SYSTEM_MULTISELECTABLE:uint = 0x01000000;
private static const STATE_SYSTEM_EXTSELECTABLE:uint = 0x02000000;
private static const STATE_SYSTEM_PROTECTED:uint = 0x20000000;
private static const STATE_SYSTEM_VALID:uint = 0x3fffffff;
private static const STATE_SYSTEM_HASPOPUP:uint = 0x40000000;

Roles

Predefined role constants (possible values of o.accRole(childId))
private static const ROLE_SYSTEM_TITLEBAR:uint = 0x1;
private static const ROLE_SYSTEM_MENUBAR:uint = 0x2;
private static const ROLE_SYSTEM_SCROLLBAR:uint = 0x3;
private static const ROLE_SYSTEM_GRIP:uint = 0x4;
private static const ROLE_SYSTEM_SOUND:uint = 0x5;
private static const ROLE_SYSTEM_CURSOR:uint = 0x6;
private static const ROLE_SYSTEM_CARET:uint = 0x7;
private static const ROLE_SYSTEM_ALERT:uint = 0x8;
private static const ROLE_SYSTEM_WINDOW:uint = 0x9;
private static const ROLE_SYSTEM_CLIENT:uint = 0xa;
private static const ROLE_SYSTEM_MENUPOPUP:uint = 0xb;
private static const ROLE_SYSTEM_MENUITEM:uint = 0xc;
private static const ROLE_SYSTEM_TOOLTIP:uint = 0xd;
private static const ROLE_SYSfTEM_APPLICATION:uint = 0xe;
private static const ROLE_SYSTEM_DOCUMENT:uint = 0xf;
private static const ROLE_SYSTEM_PANE:uint = 0x10;
private static const ROLE_SYSTEM_CHART:uint = 0x11;
private static const ROLE_SYSTEM_DIALOG:uint = 0x12;
private static const ROLE_SYSTEM_BORDER:uint = 0x13;
private static const ROLE_SYSTEM_GROUPING:uint = 0x14;
private static const ROLE_SYSTEM_SEPARATOR:uint = 0x15;
private static const ROLE_SYSTEM_TOOLBAR:uint = 0x16;
private static const ROLE_SYSTEM_STATUSBAR:uint = 0x17;
private static const ROLE_SYSTEM_TABLE:uint = 0x18;
private static const ROLE_SYSTEM_COLUMNHEADER:uint = 0x19;
private static const ROLE_SYSTEM_ROWHEADER:uint = 0x1a;
private static const ROLE_SYSTEM_COLUMN:uint = 0x1b;
private static const ROLE_SYSTEM_ROW:uint = 0x1c;
private static const ROLE_SYSTEM_CELL:uint = 0x1d;
private static const ROLE_SYSTEM_LINK:uint = 0x1e;
private static const ROLE_SYSTEM_HELPBALLOON:uint = 0x1f;
private static const ROLE_SYSTEM_CHARACTER:uint = 0x20;
private static const ROLE_SYSTEM_LIST:uint = 0x21;
private static const ROLE_SYSTEM_LISTITEM:uint = 0x22;
private static const ROLE_SYSTEM_OUTLINE:uint = 0x23;
private static const ROLE_SYSTEM_OUTLINEITEM:uint = 0x24;
private static const ROLE_SYSTEM_PAGETAB:uint = 0x25;
private static const ROLE_SYSTEM_PROPERTYPAGE:uint = 0x26;
private static const ROLE_SYSTEM_INDICATOR:uint = 0x27;
private static const ROLE_SYSTEM_GRAPHIC:uint = 0x28;
private static const ROLE_SYSTEM_STATICTEXT:uint = 0x29;
private static const ROLE_SYSTEM_TEXT:uint = 0x2a;
private static const ROLE_SYSTEM_PUSHBUTTON:uint = 0x2b;
private static const ROLE_SYSTEM_CHECKBUTTON:uint = 0x2c;
private static const ROLE_SYSTEM_RADIOBUTTON:uint = 0x2d;
private static const ROLE_SYSTEM_COMBOBOX:uint = 0x2e;
private static const ROLE_SYSTEM_DROPLIST:uint = 0x2f;
private static const ROLE_SYSTEM_PROGRESSBAR:uint = 0x30;
private static const ROLE_SYSTEM_DIAL:uint = 0x31;
private static const ROLE_SYSTEM_HOTKEYFIELD:uint = 0x32;
private static const ROLE_SYSTEM_SLIDER:uint = 0x33;
private static const ROLE_SYSTEM_SPINBUTTON:uint = 0x34;
private static const ROLE_SYSTEM_DIAGRAM:uint = 0x35;
private static const ROLE_SYSTEM_ANIMATION:uint = 0x36;
private static const ROLE_SYSTEM_EQUATION:uint = 0x37;
private static const ROLE_SYSTEM_BUTTONDROPDOWN:uint = 0x38;
private static const ROLE_SYSTEM_BUTTONMENU:uint = 0x39;
private static const ROLE_SYSTEM_BUTTONDROPDOWNGRID:uint = 0x3a;
private static const ROLE_SYSTEM_WHITESPACE:uint = 0x3b;
private static const ROLE_SYSTEM_PAGETABLIST:uint = 0x3c;
private static const ROLE_SYSTEM_CLOCK:uint = 0x3d;
private static const ROLE_SYSTEM_SPLITBUTTON:uint = 0x3e;
private static const ROLE_SYSTEM_IPADDRESS:uint = 0x3f;
private static const ROLE_SYSTEM_OUTLINEBUTTON:uint = 0x40;

Events

private static const EVENT_MIN:uint = 0x00000001;
private static const EVENT_MAX:uint = 0x7FFFFFFF;
private static const EVENT_SYSTEM_SOUND:uint = 0x0001;
private static const EVENT_SYSTEM_ALERT:uint = 0x0002;
private static const EVENT_SYSTEM_FOREGROUND:uint = 0x0003;
private static const EVENT_SYSTEM_MENUSTART:uint = 0x0004;
private static const EVENT_SYSTEM_MENUEND:uint = 0x0005;
private static const EVENT_SYSTEM_MENUPOPUPSTART:uint = 0x0006;
private static const EVENT_SYSTEM_MENUPOPUPEND:uint = 0x0007;
private static const EVENT_SYSTEM_CAPTURESTART:uint = 0x0008;
private static const EVENT_SYSTEM_CAPTUREEND:uint = 0x0009;
private static const EVENT_SYSTEM_MOVESIZESTART:uint = 0x000A;
private static const EVENT_SYSTEM_MOVESIZEEND:uint = 0x000B;
private static const EVENT_SYSTEM_CONTEXTHELPSTART:uint = 0x000C;
private static const EVENT_SYSTEM_CONTEXTHELPEND:uint = 0x000D;
private static const EVENT_SYSTEM_DRAGDROPSTART:uint = 0x000E;
private static const EVENT_SYSTEM_DRAGDROPEND:uint = 0x000F;
private static const EVENT_SYSTEM_DIALOGSTART:uint = 0x0010;
private static const EVENT_SYSTEM_DIALOGEND:uint = 0x0011;
private static const EVENT_SYSTEM_SCROLLINGSTART:uint = 0x0012;
private static const EVENT_SYSTEM_SCROLLINGEND:uint = 0x0013;
private static const EVENT_SYSTEM_SWITCHSTART:uint = 0x0014;
private static const EVENT_SYSTEM_SWITCHEND:uint = 0x0015;
private static const EVENT_SYSTEM_MINIMIZESTART:uint = 0x0016;
private static const EVENT_SYSTEM_MINIMIZEEND:uint = 0x0017;
private static const EVENT_OBJECT_CREATE:uint = 0x8000
private static const EVENT_OBJECT_DESTROY:uint = 0x8001
private static const EVENT_OBJECT_SHOW:uint = 0x8002
private static const EVENT_OBJECT_HIDE:uint = 0x8003
private static const EVENT_OBJECT_REORDER:uint = 0x8004
private static const EVENT_OBJECT_FOCUS:uint = 0x8005
private static const EVENT_OBJECT_SELECTION:uint = 0x8006
private static const EVENT_OBJECT_SELECTIONADD:uint = 0x8007
private static const EVENT_OBJECT_SELECTIONREMOVE:uint = 0x8008
private static const EVENT_OBJECT_SELECTIONWITHIN:uint = 0x8009
private static const EVENT_OBJECT_STATECHANGE:uint = 0x800A
private static const EVENT_OBJECT_LOCATIONCHANGE:uint = 0x800B
private static const EVENT_OBJECT_NAMECHANGE:uint = 0x800C
private static const EVENT_OBJECT_DESCRIPTIONCHANGE:uint = 0x800D;
private static const EVENT_OBJECT_VALUECHANGE:uint = 0x800E;
private static const EVENT_OBJECT_PARENTCHANGE:uint = 0x800F;
private static const EVENT_OBJECT_HELPCHANGE:uint = 0x8010 ;
private static const EVENT_OBJECT_DEFACTIONCHANGE:uint = 0x8011;
private static const EVENT_OBJECT_ACCELERATORCHANGE:uint = 0x8012;

TBD

New accessors on UIComponent for accessibility properties

To make it easier to set per-instance accessibility properties in MXML, we will add four new convenience getter/setters to UIComponent:

AccessibilityProperties property UIComponent convenience accessor
description accessibilityDescription
forceSimple
name accessibilityName
noAutoLabeling
shortcut accessibilityShortcut
silent accessibilityEnabled

The getters will simply return the relevant property of the UIComponent's accessibilityProperties object, or the default value if accessibilityProperties is null.

The setters will create the accessibilityProperties object if it does not yet exist, and then set the relevant property.

We will not expose convenience accessors for forceSimple or noAutoLabeling because Flex applications should not set these. Flash Player only supports a two-level hierarchy of IAccessible objects, and setting forceSimple to true in order to ignore the grandchildren doesn't seem useful. The Flash Player's auto-labeling algorithm is inappropriate for Flex apps, especially when we support "mirrored" layout for right-to-left locales.

Accessibility enabled by default

The mxmlc compiler will default to using the option -accessible=true. This results in the required accessibility implementation classes being linked in and initialized, so that each UIComponent's accessibilityImplementation is non-null.

How the MSAA AccName is constructed for form fields

The AccImpl name for a control is only part of the ultimate name of that control if the control is in a form. The full MSAA name of such a control consists of the following parts, in this order, with a space between parts:

*The form's name.
*The word "Required" if the field is required.
*The name of the form item containing the field.
*The value of AccessibilityProperties.Name.
*The AccImpl name.
*The value of GetStatusName (tooltip or error string).

API Description


New accessibility implementation classes

The new accessibility implementation classes live in the spark.accessibility package. Each one extends either mx.accessibility.AccImpl or another Spark acc impl:

New accessibility implementation class Extends
spark.accessibility.ButtonAccImpl mx.accessibility.AccImpl
   
   

They do not introduce any new properties or methods.

The ASDoc for each new class will be the description in the component links above.

MSAA constants

TBD

New accessors on UIComponent for accessibility properties

The following getter/setters will be added to UIComponent:

/**
 *  A convenience accessor for the 'silent' property
 *  in this UIComponent's accessibilityProperties object.
 *
 *  Note that accessibilityEnabled has the opposite sense from silent;
 *  accessibilityEnabled is true when silent is false and vice versa.
 *
 *  The getter simply returns accessibilityProperties.silent,
 *  or true if accessibilityProperties is null.
 *  The setter first checks whether accessibilityProperties is null, and if it is,
 *  sets it to a new AccessibilityProperties instance;
 *  then it sets accessibilityProperties.silent.
 */
public function get accessibilityEnabled():Boolean
public function set accessibilityEnabled(value:Boolean):void

/**
 *  A convenience accessor for the 'name' property
 *  in this UIComponent's accessibilityProperties object.
 *
 *  The getter simply returns accessibilityProperties.name,
 *  or "" if accessibilityProperties is null.
 *  The setter first checks whether accessibilityProperties is null, and if it is,
 *  sets it to a new AccessibilityProperties instance;
 *  then it sets accessibilityProperties.name.
 */
public function get accessibilityName():String
public function set accessibilityName(value:String):void

/**
 *  A convenience accessor for the 'description' property
 *  in this UIComponent's accessibilityProperties object.
 *
 *  The getter simply returns accessibilityProperties.description,
 *  or "" if accessibilityProperties is null.
 *  The setter first checks whether accessibilityProperties is null, and if it is,
 *  sets it to a new AccessibilityProperties instance;
 *  then it sets accessibilityProperties.description.
 */
public function get accessibilityDescription():String
public function set accessibilityDescription(value:String):void

/**
 *  A convenience accessor for the 'shortcut' property
 *  in this UIComponent's accessibilityProperties object.
 *
 *  The getter simply returns accessibilityProperties.shortcut,
 *  or "" if accessibilityProperties is null.
 *  The setter first checks whether accessibilityProperties is null, and if it is,
 *  sets it to a new AccessibilityProperties instance;
 *  then it sets accessibilityProperties.shortcut.
 */
public function get accessibilityShortcut():String
public function set accessibilityShortcut(value:String):void

B Features


None.

Examples and Usage


TBD

Additional Implementation Details


TBD

Prototype Work


None.

Compiler Work


None.

Web Tier Compiler Impact


None.

Flex Feature Dependencies


None.

Backwards Compatibility


Syntax changes

None.

Behavior

None.

Warnings/Deprecation

None.

Accessibility


That's what this feature is all about!

Performance


No performance issue.

Globalization


None.

Localization


Compiler Features

None.

Framework Features

TBD.

Issues and Recommendations


Open Issues

None.

Resolved Issues

None.

Documentation


TBD

QA


TBD

You must be logged in to comment.

Is anyone updating the AccImpl for DateField? When the halo component is editable there is no focus change event that is fired when tabbing to the control.

Regarding getName:

I ran some tests and found that what getName returns is often prepended/appended to the AccessibilityProperties.name string for the object. If you noticed the function is getName and NOT get_accName like the others. I think a get_accName is generated at some point with a combination of these strings.

There are two things that all should be aware of when creating/updating the accImpls
1. The names of the some of the Flex based events that we monitor in the AccImpls may have changed. All events should be double checked and tested with Event32.exe to ensure they are still firing for assistive technology.
2. There are many Flex bugs in bugs.adobe.com that relate to the components – bug fixes should be applied to the relevant components when possible. Please review the Jira site to find out what bugs are related to your AccImpl.