Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

a11y: Add SemanticsAction "showOnScreen" #3856

Merged
merged 1 commit into from
Jul 12, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions lib/ui/semantics.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ 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;

/// The numerical value for this action.
///
Expand Down Expand Up @@ -69,6 +70,12 @@ class SemanticsAction {
/// For example, this action might be recognized by a slider control.
static const SemanticsAction decrease = const SemanticsAction._(_kDecreaseIndex);

/// A request to fully show the semantics node on screen.
///
/// 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);

/// The possible semantics actions.
///
/// The map's key is the [index] of the action and the value is the action
Expand All @@ -82,6 +89,7 @@ class SemanticsAction {
_kScrollDownIndex: scrollDown,
_kIncreaseIndex: increase,
_kDecreaseIndex: decrease,
_kShowOnScreen: showOnScreen,
};

@override
Expand All @@ -103,6 +111,8 @@ class SemanticsAction {
return 'SemanticsAction.increase';
case _kDecreaseIndex:
return 'SemanticsAction.decrease';
case _kShowOnScreen:
return 'SemanticsAction.showOnScreen';
}
return null;
}
Expand Down
12 changes: 11 additions & 1 deletion shell/platform/android/io/flutter/view/AccessibilityBridge.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class AccessibilityBridge extends AccessibilityNodeProvider {
private static final int SEMANTICS_ACTION_SCROLL_DOWN = 1 << 5;
private static final int SEMANTICS_ACTION_INCREASE = 1 << 6;
private static final int SEMANTICS_ACTION_DECREASE = 1 << 7;
private static final int SEMANTICS_ACTION_SHOW_ON_SCREEN = 1 << 8;

private static final int SEMANTICS_ACTION_SCROLLABLE = SEMANTICS_ACTION_SCROLL_LEFT |
SEMANTICS_ACTION_SCROLL_RIGHT |
Expand Down Expand Up @@ -77,7 +78,7 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) {

AccessibilityNodeInfo result = AccessibilityNodeInfo.obtain(mOwner, virtualViewId);
result.setPackageName(mOwner.getContext().getPackageName());
result.setClassName("Flutter"); // Prettier than the more conventional node.getClass().getName()
result.setClassName("Flutter"); // TODO(goderbauer): Set proper class names
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Android TalkBack uses the class to determine how to behave (for an example see below where I set the class to ScrollView to get the correct scroll behavoir). And if you set the class to button for example, Android talkback will correctly announce that it is a button. There are more classes with special meaning, apparently.

result.setSource(mOwner, virtualViewId);

if (object.parent != null) {
Expand Down Expand Up @@ -117,6 +118,9 @@ public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) {
result.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
result.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
result.setScrollable(true);
// This tells Android's a11y to send scroll events when reaching the end of
// the visible viewport of a scrollable.
result.setClassName("android.widget.ScrollView");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see. The magic is to fake which class you are?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. That's exactly it.

}

result.setCheckable((object.flags & SEMANTICS_FLAG_HAS_CHECKED_STATE) != 0);
Expand Down Expand Up @@ -199,6 +203,12 @@ public boolean performAction(int virtualViewId, int action, Bundle arguments) {
mFocusedObject = object;
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
mOwner.dispatchSemanticsAction(virtualViewId, SEMANTICS_ACTION_SHOW_ON_SCREEN);
return true;
}
}
return false;
}
Expand Down