未验证 提交 7c34dfaf 编写于 作者: M Michael Goderbauer 提交者: GitHub

Adds a11y action for selecting text (and moving cursor) (#4589)

See https://github.com/flutter/flutter/pull/14275 for framework side change.

Also includes some minor clean-ups for consistency. 

Required for https://github.com/flutter/flutter/issues/13469.
上级 4c82c566
......@@ -17,9 +17,10 @@ class SemanticsAction {
static const int _kScrollDownIndex = 1 << 5;
static const int _kIncreaseIndex = 1 << 6;
static const int _kDecreaseIndex = 1 << 7;
static const int _kShowOnScreen = 1 << 8;
static const int _kMoveCursorForwardByCharacter = 1 << 9;
static const int _kMoveCursorBackwardByCharacter = 1 << 10;
static const int _kShowOnScreenIndex = 1 << 8;
static const int _kMoveCursorForwardByCharacterIndex = 1 << 9;
static const int _kMoveCursorBackwardByCharacterIndex = 1 << 10;
static const int _kSetSelectionIndex = 1 << 11;
/// The numerical value for this action.
///
......@@ -76,18 +77,35 @@ class SemanticsAction {
///
/// For example, this action might be send to a node in a scrollable list that
/// is partially off screen to bring it on screen.
static const SemanticsAction showOnScreen = const SemanticsAction._(_kShowOnScreen);
static const SemanticsAction showOnScreen = const SemanticsAction._(_kShowOnScreenIndex);
/// Move the cursor forward by one character.
///
/// This is for example used by the cursor control in text fields.
static const SemanticsAction moveCursorForwardByCharacter = const SemanticsAction._(_kMoveCursorForwardByCharacter);
///
/// The action includes a boolean argument, which indicates whether the cursor
/// movement should extend (or start) a selection.
static const SemanticsAction moveCursorForwardByCharacter = const SemanticsAction._(_kMoveCursorForwardByCharacterIndex);
/// Move the cursor backward by one character.
///
/// This is for example used by the cursor control in text fields.
static const SemanticsAction moveCursorBackwardByCharacter = const SemanticsAction._(_kMoveCursorBackwardByCharacter);
///
/// The action includes a boolean argument, which indicates whether the cursor
/// movement should extend (or start) a selection.
static const SemanticsAction moveCursorBackwardByCharacter = const SemanticsAction._(_kMoveCursorBackwardByCharacterIndex);
/// Set the text selection to the given range.
///
/// The provided argument is a Map<String, int> which includes the keys `base`
/// and `extent` indicating where the selection within the `value` of the
/// semantics node should start and where it should end. Values for both
/// keys can range from 0 to length of `value` (inclusive).
///
/// Setting `base` and `extent` to the same value will move the cursor to
/// that position (without selecting anything).
static const SemanticsAction setSelection = const SemanticsAction._(_kSetSelectionIndex);
/// The possible semantics actions.
///
......@@ -102,9 +120,10 @@ class SemanticsAction {
_kScrollDownIndex: scrollDown,
_kIncreaseIndex: increase,
_kDecreaseIndex: decrease,
_kShowOnScreen: showOnScreen,
_kMoveCursorForwardByCharacter: moveCursorForwardByCharacter,
_kMoveCursorBackwardByCharacter: moveCursorBackwardByCharacter,
_kShowOnScreenIndex: showOnScreen,
_kMoveCursorForwardByCharacterIndex: moveCursorForwardByCharacter,
_kMoveCursorBackwardByCharacterIndex: moveCursorBackwardByCharacter,
_kSetSelectionIndex: setSelection,
};
@override
......@@ -126,12 +145,14 @@ class SemanticsAction {
return 'SemanticsAction.increase';
case _kDecreaseIndex:
return 'SemanticsAction.decrease';
case _kShowOnScreen:
case _kShowOnScreenIndex:
return 'SemanticsAction.showOnScreen';
case _kMoveCursorForwardByCharacter:
case _kMoveCursorForwardByCharacterIndex:
return 'SemanticsAction.moveCursorForwardByCharacter';
case _kMoveCursorBackwardByCharacter:
case _kMoveCursorBackwardByCharacterIndex:
return 'SemanticsAction.moveCursorBackwardByCharacter';
case _kSetSelectionIndex:
return 'SemanticsAction.setSelection';
}
return null;
}
......
......@@ -31,6 +31,11 @@ import java.util.Set;
class AccessibilityBridge extends AccessibilityNodeProvider implements BasicMessageChannel.MessageHandler<Object> {
private static final String TAG = "FlutterView";
// Constants from higher API levels.
// TODO(goderbauer): Get these from Android Support Library when
// https://github.com/flutter/flutter/issues/11099 is resolved.
public static final int ACTION_SHOW_ON_SCREEN = 16908342; // API level 23
private Map<Integer, SemanticsObject> mObjects;
private final FlutterView mOwner;
private boolean mAccessibilityEnabled = false;
......@@ -51,7 +56,8 @@ class AccessibilityBridge extends AccessibilityNodeProvider implements BasicMess
DECREASE(1 << 7),
SHOW_ON_SCREEN(1 << 8),
MOVE_CURSOR_FORWARD_BY_CHARACTER(1 << 9),
MOVE_CURSOR_BACKWARD_BY_CHARACTER(1 << 10);
MOVE_CURSOR_BACKWARD_BY_CHARACTER(1 << 10),
SET_SELECTION(1 << 11);
Action(int value) {
this.value = value;
......@@ -142,6 +148,9 @@ class AccessibilityBridge extends AccessibilityNodeProvider implements BasicMess
}
result.setMovementGranularities(granularities);
}
if (object.hasAction(Action.SET_SELECTION)) {
result.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION);
}
if (object.hasFlag(Flag.IS_BUTTON)) {
result.setClassName("android.widget.Button");
......@@ -317,12 +326,30 @@ class AccessibilityBridge extends AccessibilityNodeProvider implements BasicMess
return true;
}
// TODO(goderbauer): Use ACTION_SHOW_ON_SCREEN from Android Support Library after
// https://github.com/flutter/flutter/issues/11099 is resolved.
case 16908342: { // ACTION_SHOW_ON_SCREEN, added in API level 23
case ACTION_SHOW_ON_SCREEN: {
mOwner.dispatchSemanticsAction(virtualViewId, Action.SHOW_ON_SCREEN);
return true;
}
case AccessibilityNodeInfo.ACTION_SET_SELECTION: {
final Map<String, Integer> selection = new HashMap<String, Integer>();
final boolean hasSelection = arguments != null
&& arguments.containsKey(
AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT)
&& arguments.containsKey(
AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT);
if (hasSelection) {
selection.put("base", arguments.getInt(
AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT));
selection.put("extent", arguments.getInt(
AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT));
} else {
// Clear the selection
selection.put("base", object.textSelectionExtent);
selection.put("extent", object.textSelectionExtent);
}
mOwner.dispatchSemanticsAction(virtualViewId, Action.SET_SELECTION, selection);
return true;
}
}
return false;
}
......@@ -467,7 +494,7 @@ class AccessibilityBridge extends AccessibilityNodeProvider implements BasicMess
object.id, AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED);
selectionEvent.getText().add(newValue);
selectionEvent.setFromIndex(object.textSelectionBase);
selectionEvent.setToIndex(object.previousTextSelectionExtent);
selectionEvent.setToIndex(object.textSelectionExtent);
selectionEvent.setItemCount(newValue.length());
sendAccessibilityEvent(selectionEvent);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册