/* * ScreenReaderHandler.java * * Copyright � 1998-2011 Research In Motion Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Note: For the sake of simplicity, this sample application may not leverage * resource bundles and resource strings. However, it is STRONGLY recommended * that application developers make use of the localization features available * within the BlackBerry development platform to ensure a seamless application * experience across a variety of languages and geographies. For more information * on localizing your application, please refer to the BlackBerry Java Development * Environment Development Guide associated with this release. */ package com.rim.samples.device.accessibilitydemo.screenreaderdemo; import net.rim.device.api.ui.accessibility.AccessibleContext; import net.rim.device.api.ui.accessibility.AccessibleDateField; import net.rim.device.api.ui.accessibility.AccessibleState; import net.rim.device.api.ui.accessibility.AccessibleTable; import net.rim.device.api.ui.accessibility.AccessibleText; /** * This class provides methods that handle the various accessible events * specific to components defined by the AccessibleRole interface. */ public final class ScreenReaderHandler { private static AccessibleContext _currentScreen; /** * Handles event generated by accessible component with role * AccessibleRole.APP_ICON * * @param event * Accessible event that occured * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ static void handleAppIcon(final int event, final int oldValue, final int newValue, final AccessibleContext context) { if (event == AccessibleContext.ACCESSIBLE_STATE_CHANGED) { if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.FOCUSED)) { final String appName = context.getAccessibleName(); Util.speak(appName + " icon focused"); } } } /** * Handles event generated by accessible component with role * AccessibleRole.ICON * * @param event * Accessible event that occured * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ static void handleIcon(final int event, final int oldValue, final int newValue, final AccessibleContext context) { if (event == AccessibleContext.ACCESSIBLE_STATE_CHANGED) { if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.FOCUSED)) { final String appName = context.getAccessibleName(); Util.speak(appName + " icon focused"); } } } /** * Handles event generated by accessible component with role * AccessibleRole.CHECKBOX * * @param event * Accessible event that occured * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ static void handleCheckBox(final int event, final int oldValue, final int newValue, final AccessibleContext context) { if (event == AccessibleContext.ACCESSIBLE_STATE_CHANGED) { String checkBoxLabel = context.getAccessibleName(); if (checkBoxLabel == null) { checkBoxLabel = ""; } if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.FOCUSED)) { final boolean checked = (newValue & AccessibleState.CHECKED) != 0; final String checkedSpeech = checked ? "checked" : "unchecked"; Util.speak("Check box " + checkBoxLabel + " focused " + checkedSpeech); } else if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.CHECKED)) { Util.speak("Check box " + checkBoxLabel + " checked"); } else if (Util.hasTransitionedFromState(oldValue, newValue, AccessibleState.CHECKED)) { Util.speak("Check box " + checkBoxLabel + " unchecked"); } else if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.MOUSE_OVER)) { Util.speak("Mouse over check box " + checkBoxLabel); } } } /** * Handles event generated by accessible component with role * AccessibleRole.DATE * * @param event * Accessible event that occured * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ static void handleDate(final int event, final int oldValue, final int newValue, final AccessibleContext context) { if (event == AccessibleContext.ACCESSIBLE_STATE_CHANGED) { String dateFieldLabel = context.getAccessibleName(); if (dateFieldLabel == null) { dateFieldLabel = ""; } final AccessibleText text = context.getAccessibleText(); if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.FOCUSED)) { Util.speak("Date field " + dateFieldLabel + " focused"); } else if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.EXPANDED)) { Util.speak("Date field " + dateFieldLabel + " expanded"); } else if (Util.hasTransitionedFromState(oldValue, newValue, AccessibleState.EXPANDED)) { Util.speak("Date field " + dateFieldLabel + " collapsed"); } if (text != null) { Util.speak("Current value " + text.getWholeText()); } } } /** * Handles event generated by accessible component with role * AccessibleRole.DATE_FIELD * * @param event * Accessible event that occured * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ static void handleDateField(final int event, final int oldValue, final int newValue, final AccessibleContext context) { switch (event) { case AccessibleContext.ACCESSIBLE_STATE_CHANGED: if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.FOCUSED)) { final AccessibleDateField dateField = (AccessibleDateField) context; final String dateSubfieldString = Util.getDateSubfieldString(dateField.getDateFieldType()); Util.speak(dateSubfieldString + " focused"); } break; case AccessibleContext.ACCESSIBLE_VALUE_CHANGED: final AccessibleDateField dateField = (AccessibleDateField) context; final String dateSubfieldString = Util.getDateSubfieldString(dateField.getDateFieldType()); Util.speak(dateSubfieldString + " value changed"); Util.speak("New value " + context.getAccessibleName()); break; } } /** * Handles event generated by accessible component with role * AccessibleRole.DIALOG * * @param event * Accessible event that occured * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ static void handleDialog(final int event, final int oldValue, final int newValue, final AccessibleContext context) { if (event == AccessibleContext.ACCESSIBLE_STATE_CHANGED) { if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.ACTIVE)) { // Dialog became active, read it. Util.speak("New dialog opened " + context.getAccessibleName()); for (int i = 0; i < context.getAccessibleChildCount(); i++) { final AccessibleContext child = context.getAccessibleChildAt(i); ChildReader.readChildElement(child); } } } } /** * Handles event generated by accessible component with role * AccessibleRole.PANEL * * @param event * Accessible event that occured * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ static void handlePanel(final int event, final int oldValue, final int newValue, final AccessibleContext context) { if (event == AccessibleContext.ACCESSIBLE_STATE_CHANGED) { if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.AVAILABLE)) { Util.speak("Page Loaded"); ChildReader.readChildElement(context); } if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.FOCUSED)) { Util.speak(context.getAccessibleName() + " focused"); ChildReader.readChildElement(context); } } } /** * Handles event generated by accessible component with role * AccessibleRole.CHOICE * * @param event * Accessible event that occured * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ static void handleChoice(final int event, final int oldValue, final int newValue, final AccessibleContext context) { String name = context.getAccessibleName(); if (name == null) { name = ""; } switch (event) { case AccessibleContext.ACCESSIBLE_STATE_CHANGED: if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.EXPANDED)) { final int childCount = context.getAccessibleChildCount(); Util.speak("Choice field " + name + " expanded with " + childCount + " elements"); // Read a maximum of 10 items. final int maxRead = Math.min(10, childCount); for (int i = 0; i < maxRead; i++) { final AccessibleContext child = context.getAccessibleChildAt(i); if (child != null) { final int childState = child.getAccessibleStateSet(); final boolean childSelected = (childState & AccessibleState.SELECTED) != 0; Util.speak(child.getAccessibleName() + (childSelected ? " selected" : "")); } } } else if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.COLLAPSED)) { Util.speak("Choice field " + name + " collapsed "); final AccessibleContext child = context.getAccessibleSelectionAt(0); if (child != null) { Util.speak(child.getAccessibleName() + " selected"); } } else if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.FOCUSED)) { Util.speak("Choice field " + name + " focused"); final AccessibleContext child = context.getAccessibleSelectionAt(0); if (child != null) { Util.speak("Current value " + child.getAccessibleName()); } } else if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.MOUSE_OVER)) { Util.speak("Mouse over choice field " + name); } break; case AccessibleContext.ACCESSIBLE_SELECTION_CHANGED: final AccessibleContext child = context.getAccessibleSelectionAt(0); if (child != null) { Util.speak(child.getAccessibleName() + " selected"); } break; } } /** * Handles event generated by accessible component with role * AccessibleRole.COMBO * * @param event * Accessible event that occured * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ static void handleCombo(final int event, final int oldValue, final int newValue, final AccessibleContext context) { String name = context.getAccessibleName(); if (name == null) { name = ""; } switch (event) { case AccessibleContext.ACCESSIBLE_STATE_CHANGED: if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.FOCUSED)) { Util.speak("combo box " + name + " focused"); } else if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.EXPANDED)) { Util.speak("combo box " + name + " expanded"); } else if (Util.hasTransitionedFromState(oldValue, newValue, AccessibleState.EXPANDED)) { Util.speak("combo box " + name + " collapsed"); } break; case AccessibleContext.ACCESSIBLE_CHILD_CHANGED: // New values in the combo box drop-down list. final AccessibleContext comboDropDownList = context.getAccessibleChildAt(1); final int childCount = comboDropDownList != null ? comboDropDownList .getAccessibleChildCount() : 0; final int maxCount = Math.min(childCount, 10); Util.speak("combo box " + name + " drop down values changed"); for (int i = 0; i < maxCount; i++) { final AccessibleContext child = comboDropDownList.getAccessibleChildAt(i); ChildReader.readChildElement(child); } break; } } /** * Handles event generated by accessible component with role * AccessibleRole.BITMAP * * @param event * Accessible event that occured * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ static void handleBitmap(final int event, final int oldValue, final int newValue, final AccessibleContext context) { if (event == AccessibleContext.ACCESSIBLE_STATE_CHANGED) { if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.MOUSE_OVER)) { String name = context.getAccessibleName(); if (name == null) { name = ""; } Util.speak("Mouse over image " + name); } } } /** * Handles event generated by accessible component with role * AccessibleRole.TABLE * * @param event * Accessible event that occured * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ static void handleTable(final int event, final int oldValue, final int newValue, final AccessibleContext context) { final AccessibleTable table = context.getAccessibleTable(); if (table == null) { System.out .println("Accessible Table doesn't provide table interface"); return; } String name = context.getAccessibleName(); if (name == null) { name = ""; } switch (event) { case AccessibleContext.ACCESSIBLE_STATE_CHANGED: if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.AVAILABLE)) { Util.speak("Table " + name + " loaded"); ChildReader.readTableElement(context); } break; case AccessibleContext.ACCESSIBLE_SELECTION_CHANGED: handleTableSelection(table); break; case AccessibleContext.ACCESSIBLE_CHILD_CHANGED: Util.speak("table " + name + " changed"); ChildReader.readChildElement(context); break; } } /** * Helper method for handleTable() */ static void handleTableSelection(final AccessibleTable table) { final AccessibleContext[] tableColumns = table.getAccessibleColumnHeader(); final AccessibleContext[] tableRows = table.getAccessibleRowHeader(); final int[] selectedRows = table.getSelectedAccessibleRows(); final int[] selectedColumns = table.getSelectedAccessibleColumns(); if (selectedRows.length == 0 || selectedColumns.length == 0) { // No cells selected. Util.speak("no table cells selected"); } else if (selectedRows.length == 1 && selectedColumns.length == 1) { // One cell selected. final int row = selectedRows[0]; final int col = selectedColumns[0]; String rowCaption = tableRows != null ? tableRows[row].getAccessibleName() : "" + (row + 1); String colCaption = tableColumns != null ? tableColumns[col] .getAccessibleName() : "" + (col + 1); if (rowCaption == null) { rowCaption = "" + (row + 1); } if (colCaption == null) { colCaption = "" + (col + 1); } Util.speak("One cell selected column " + colCaption + " row " + rowCaption); final AccessibleContext cell = table.getAccessibleAt(row, col); if (cell != null) { ChildReader.readChildElement(cell); } else { Util.speak("cell empty"); } } else if (selectedColumns.length == 1) { // Multiple rows in one cell selected. final int col = selectedColumns[0]; final int rowCount = selectedRows.length; String startRowCaption = tableRows != null ? tableRows[selectedRows[0]] .getAccessibleName() : "" + (selectedRows[0] + 1); final String endRowCaption = tableRows != null ? tableRows[selectedRows[rowCount - 1]] .getAccessibleName() : "" + (selectedRows[rowCount - 1] + 1); String colCaption = tableColumns != null ? tableColumns[col] .getAccessibleName() : "column " + (col + 1); if (startRowCaption == null) { startRowCaption = "" + (selectedRows[0] + 1); } if (colCaption == null) { colCaption = "" + (selectedRows[rowCount - 1] + 1); } Util.speak(rowCount + " cells selected in column " + colCaption); Util.speak("start row " + startRowCaption + " end row " + endRowCaption); boolean cellFilled = false; for (int i = 0; i < selectedRows.length; i++) { final AccessibleContext selected = table.getAccessibleAt(selectedRows[i], col); if (selected != null) { ChildReader.readChildElement(selected); cellFilled = true; } } if (!cellFilled) { Util.speak("all selected cells are empty"); } } } /** * Handles event generated by accessible component with role * AccessibleRole.HYPERLINK * * @param event * Accessible event that occured * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ static void handleHyperLink(final int event, final int oldValue, final int newValue, final AccessibleContext context) { if (event == AccessibleContext.ACCESSIBLE_STATE_CHANGED) { if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.MOUSE_OVER)) { Util.speak("mouse over hyperlink " + context.getAccessibleName()); } } } /** * Handles event generated by accessible component with role * AccessibleRole.GAUGE * * @param event * Accessible event that occured * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ static void handleGauge(final int event, final int oldValue, final int newValue, final AccessibleContext context) { final String name = context.getAccessibleName(); switch (event) { case AccessibleContext.ACCESSIBLE_VALUE_CHANGED: { Util.speak(name + " value changed to " + context.getAccessibleValue().getCurrentAccessibleValue()); break; } case AccessibleContext.ACCESSIBLE_STATE_CHANGED: { if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.FOCUSED)) { Util.speak(name + " focused "); Util.speak(name + "value " + context.getAccessibleValue() .getCurrentAccessibleValue()); } } } } /** * Handles event generated by accessible component with role * AccessibleRole.LABEL * * @param event * Accessible event that occured * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ static void handleLabel(final int event, final int oldValue, final int newValue, final AccessibleContext label) { String name = label.getAccessibleName(); name = name != null ? name : ""; if (event == AccessibleContext.ACCESSIBLE_STATE_CHANGED) { if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.FOCUSED)) { Util.speak(name + " focused"); } else if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.SELECTED)) { Util.speak(name + " selected"); } else if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.EXPANDED)) { Util.speak(name + " expanded"); } else if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.COLLAPSED)) { Util.speak(name + " collapsed"); } else if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.MOUSE_OVER)) { Util.speak("mouse over " + name); } } } /** * Handles event generated by accessible component with role * AccessibleRole.MENU * * @param event * Accessible event that occured * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ static void handleMenu(final int event, final int oldValue, final int newValue, final AccessibleContext context) { if (event == AccessibleContext.ACCESSIBLE_STATE_CHANGED) { if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.ACTIVE)) { // Find active menu item. final int childCount = context.getAccessibleChildCount(); final String orientation = Util.getOrientation(context.getAccessibleStateSet()); Util.speak(orientation + " menu opened total " + childCount + " items"); final int readMax = Math.min(10, childCount); for (int i = 0; i < readMax; i++) { final AccessibleContext child = context.getAccessibleChildAt(i); ChildReader.readChildElement(child); } } else if (Util.hasTransitionedFromState(oldValue, newValue, AccessibleState.ACTIVE)) { Util.speak("menu closed"); } } } /** * Handles event generated by accessible component with role * AccessibleRole.MENU_ITEM * * @param event * Accessible event that occured * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ static void handleMenuItem(final int event, final int oldValue, final int newValue, final AccessibleContext context) { if (event == AccessibleContext.ACCESSIBLE_STATE_CHANGED) { if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.SELECTED)) { Util.speak(context.getAccessibleName() + " menu item selected"); } } } /** * Handles event generated by accessible component with role * AccessibleRole.PUSH_BUTTON * * @param event * Accessible event that occured * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ static void handlePushButton(final int event, final int oldValue, final int newValue, final AccessibleContext context) { String name = context.getAccessibleName(); if (name == null) { name = ""; } if (event == AccessibleContext.ACCESSIBLE_STATE_CHANGED) { if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.FOCUSED)) { Util.speak("button " + name + " focused"); } else if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.PUSHED)) { Util.speak("button " + name + " pushed"); } else if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.MOUSE_OVER)) { Util.speak("mouse over button " + name); } } } /** * Handles event generated by accessible component with role * AccessibleRole.RADIO_BUTTON * * @param event * Accessible event that occured * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ static void handleRadioButton(final int event, final int oldValue, final int newValue, final AccessibleContext context) { String name = context.getAccessibleName(); if (name == null) { name = ""; } if (oldValue == AccessibleState.UNSET && newValue == AccessibleState.FOCUSED) { if (event == AccessibleContext.ACCESSIBLE_STATE_CHANGED) { Util.speak("radio button " + name); } } if (oldValue == AccessibleState.FOCUSED && newValue == AccessibleState.SELECTED) { if (event == AccessibleContext.ACCESSIBLE_STATE_CHANGED) { Util.speak("radio button " + name); Util.speak("Selected"); } } } /** * Handles event generated by accessible component with role * AccessibleRole.SCREEN * * @param event * Accessible event that occured * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ static void handleScreen(final int event, final int oldValue, final int newValue, final AccessibleContext screen) { switch (event) { case AccessibleContext.ACCESSIBLE_STATE_CHANGED: if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.ACTIVE)) { // Screen became active, read it. if (_currentScreen != screen) { _currentScreen = screen; Util.speak("new screen activated"); ChildReader.readChildElement(screen); } } break; case AccessibleContext.ACCESSIBLE_CHILD_CHANGED: if (_currentScreen == screen) { // Notify of the change. Util.speak("screen content changed"); ChildReader.readChildElement(screen); } break; } } /** * Handles event generated by accessible component with role * AccessibleRole.LIST * * @param event * Accessible event that occured * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ static void handleList(final int event, final int oldValue, final int newValue, final AccessibleContext list) { String name = list.getAccessibleName(); name = name != null ? name : ""; switch (event) { case AccessibleContext.ACCESSIBLE_STATE_CHANGED: if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.FOCUSED)) { final String orientation = Util.getOrientation(list.getAccessibleStateSet()); Util.speak(orientation + " list " + name + " focused total " + list.getAccessibleChildCount() + " elements"); handleListSelection(list); } else if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.AVAILABLE)) { Util.speak("list " + name + " loaded"); ChildReader.readChildElement(list); } break; case AccessibleContext.ACCESSIBLE_CHILD_CHANGED: Util.speak("list " + name + " changed"); ChildReader.readChildElement(list); break; case AccessibleContext.ACCESSIBLE_SELECTION_CHANGED: handleListSelection(list); break; } } /** * Helper method for handleList() * * @param list * Field on which event occured */ private static void handleListSelection(final AccessibleContext list) { final int selectedCount = list.getAccessibleSelectionCount(); String name = list.getAccessibleName(); if (name == null) { name = ""; } if (selectedCount == 0) { Util.speak("no elements selected"); } else if (selectedCount == 1) { final AccessibleContext selectedChild = list.getAccessibleSelectionAt(0); if (selectedChild == null) { Util.speak("null Selection! in the list " + name); } else { Util.speak(selectedChild.getAccessibleName() + " selected in the list " + name); } } else { Util.speak(selectedCount + " rows selected"); final int readMax = Math.min(5, selectedCount); for (int i = 0; i < readMax; i++) { ChildReader.readChildElement(list.getAccessibleSelectionAt(i)); } } } /** * Handles event generated by accessible component with role * AccessibleRole.SYMBOL * * @param event * Accessible event that occured * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ static void handleSymbol(final int event, final int oldValue, final int newValue, final AccessibleContext context) { final int count = context.getAccessibleChildCount(); int index; for (index = count - 1; index >= 0; index--) { if (context.isAccessibleChildSelected(index)) { ++index; break; } } final AccessibleContext item = context.getAccessibleSelectionAt(0); final String output = "Symbol: " + item.getAccessibleName() + ". " + index + " out of " + count; Util.speak(output); } /** * Handles event generated by accessible component with role * AccessibleRole.TREE_FIELD * * @param event * Accessible event that occured * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ static void handleTreeField(final int event, final int oldValue, final int newValue, final AccessibleContext context) { switch (event) { case AccessibleContext.ACCESSIBLE_SELECTION_CHANGED: final AccessibleContext selectedChild = context.getAccessibleSelectionAt(0); String name = selectedChild.getAccessibleName(); if (name == null) { name = ""; } final int states = selectedChild.getAccessibleStateSet(); final String expandableText = (states & AccessibleState.EXPANDABLE) != 0 ? " expandable" : ""; Util.speak(name + " node selected" + expandableText); break; case AccessibleContext.ACCESSIBLE_STATE_CHANGED: AccessibleContext item = null; final int count = context.getAccessibleChildCount(); if (count != 0) { item = context.getAccessibleSelectionAt(0); if (item != null) { String name2 = item.getAccessibleName(); if (name2 == null) { name2 = ""; } if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.EXPANDED)) { Util.speak(name2 + " node expanded"); } else if (Util.hasTransitionedToState(oldValue, newValue, AccessibleState.COLLAPSED)) { Util.speak(name2 + " node collapsed"); } } } break; } } /** * Handles event generated by accessible component with role * AccessibleRole.TEXT_FIELD * * @param event * Accessible event that occured * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ static void handleTextField(final int event, final Object oldValue, final Object newValue, final AccessibleContext context) { int _oldValue = AccessibleState.UNSET; int _newValue = AccessibleState.UNSET; if (oldValue instanceof Integer) { _oldValue = ((Integer) oldValue).intValue(); } if (newValue instanceof Integer) { _newValue = ((Integer) newValue).intValue(); } String name = context.getAccessibleName(); if (name == null) { name = ""; } final AccessibleText aText = context.getAccessibleText(); switch (event) { case AccessibleContext.ACCESSIBLE_STATE_CHANGED: if (Util.hasTransitionedToState(_oldValue, _newValue, AccessibleState.FOCUSED)) { final boolean editable = (_newValue & AccessibleState.EDITABLE) != 0; final boolean selectable = (_newValue & AccessibleState.SELECTABLE) != 0; final String editableString = editable ? " editable" : ""; String value; if (selectable) { value = aText != null ? aText.getAtIndex( AccessibleText.LINE, aText .getCaretPosition()) : null; } else { value = aText.getWholeText(); } Util.speak(name + " focused " + editableString); if (value != null) { Util.speak(name + " text " + value); } } else if (Util.hasTransitionedToState(_oldValue, _newValue, AccessibleState.SELECTED)) { Util.speak("text field " + name + " enable selecting mode"); } else if (Util.hasTransitionedFromState(_oldValue, _newValue, AccessibleState.SELECTED)) { Util.speak("text field " + name + " disable selecting mode"); } else if (Util.hasTransitionedToState(_oldValue, _newValue, AccessibleState.MOUSE_OVER)) { Util.speak("mouse over text field " + name); } break; case AccessibleContext.ACCESSIBLE_TEXT_CHANGED: handleTextChanged((String) oldValue, (String) newValue, context); break; case AccessibleContext.ACCESSIBLE_CARET_CHANGED: final String oldLine = aText.getAtIndex(AccessibleText.LINE, _oldValue + 1); if (Math.abs(_oldValue - _newValue) == 1 && oldLine.length() != 0) { // Sample handling indicates horizontal scroll occurred - says // the char. Util.speak(aText.getAtIndex(AccessibleText.CHAR, aText .getCaretPosition())); } else { // Sample handling indicates vertical scroll occurred - says the // line. Util.speak(aText.getAtIndex(AccessibleText.LINE, ++_newValue)); } break; } } /** * Helper method for handleTextField() * * @param oldValue * Depends on event type * @param newValue * Depends on event type * @param context * Field on which event occured */ private static void handleTextChanged(final String oldValue, final String newValue, final AccessibleContext context) { final AccessibleText aText = context.getAccessibleText(); if (aText != null) { if (oldValue == null && newValue != null) { System.out.println("Text: Insert: " + newValue); System.out.println("Word At: " + aText.getAtIndex(AccessibleText.WORD, aText .getCaretPosition())); } else if (oldValue != null && newValue == null) { System.out.println("Text: Delete: " + oldValue); } else if (oldValue != null && newValue != null) { System.out.println("Text: Replace: " + oldValue + " with " + newValue); } } } }