Commit ec072c3e authored by Mark Schillaci's avatar Mark Schillaci Committed by Commit Bot

Exposing link <a> nested structure to TalkBack on Android

This CL addresses issues with complex structures nested inside links
on Android. We now never consider a link as a leaf node to ensure
that the entire structure is traversable. We update the method
IsInterestingOnAndroid to make simple cases un-interesting to prevent
double navigation issues. We also change the AccessibilityNodeInfo
passed to TalkBack to prevent structure from being too verbose
when read.

Unit test expectations updated to account for change.

Bug: 1018555
Change-Id: I0b0d60f0ec69f400023c21ad92f3fbe69f08d378
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1955098
Commit-Queue: Mark Schillaci <mschillaci@google.com>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#737936}
parent 3cbcdbe2
...@@ -139,6 +139,10 @@ bool BrowserAccessibilityAndroid::PlatformIsLeafIncludingIgnored() const { ...@@ -139,6 +139,10 @@ bool BrowserAccessibilityAndroid::PlatformIsLeafIncludingIgnored() const {
break; break;
} }
// Links are never a leaf
if (IsLink())
return false;
// If it has a focusable child, we definitely can't leave out children. // If it has a focusable child, we definitely can't leave out children.
if (HasFocusableNonOptionChild()) if (HasFocusableNonOptionChild())
return false; return false;
...@@ -373,6 +377,14 @@ bool BrowserAccessibilityAndroid::IsInterestingOnAndroid() const { ...@@ -373,6 +377,14 @@ bool BrowserAccessibilityAndroid::IsInterestingOnAndroid() const {
if (ui::IsControl(GetRole())) if (ui::IsControl(GetRole()))
return true; return true;
// If we are the direct descendant of a link and have no siblings/children,
// then we are not interesting, return false
parent = PlatformGetParent();
if (parent != nullptr && ui::IsLink(parent->GetRole()) &&
parent->PlatformChildCount() == 1 && PlatformChildCount() == 0) {
return false;
}
// Otherwise, the interesting nodes are leaf nodes with non-whitespace text. // Otherwise, the interesting nodes are leaf nodes with non-whitespace text.
return PlatformIsLeaf() && return PlatformIsLeaf() &&
!base::ContainsOnlyChars(GetInnerText(), base::kWhitespaceUTF16); !base::ContainsOnlyChars(GetInnerText(), base::kWhitespaceUTF16);
......
...@@ -1313,8 +1313,14 @@ public class WebContentsAccessibilityImpl extends AccessibilityNodeProvider ...@@ -1313,8 +1313,14 @@ public class WebContentsAccessibilityImpl extends AccessibilityNodeProvider
int[] suggestionEnds, String[] suggestions) { int[] suggestionEnds, String[] suggestions) {
CharSequence computedText = computeText( CharSequence computedText = computeText(
text, isEditableText, language, suggestionStarts, suggestionEnds, suggestions); text, isEditableText, language, suggestionStarts, suggestionEnds, suggestions);
// We expose the nested structure of links, which results in the roles of all nested nodes
// being read. Use content description in the case of links to prevent verbose TalkBack
if (annotateAsLink) {
node.setContentDescription(computedText);
} else {
node.setText(computedText); node.setText(computedText);
} }
}
protected CharSequence computeText(String text, boolean annotateAsLink, String language, protected CharSequence computeText(String text, boolean annotateAsLink, String language,
int[] suggestionStarts, int[] suggestionEnds, String[] suggestions) { int[] suggestionStarts, int[] suggestionEnds, String[] suggestions) {
......
android.webkit.WebView focusable focused scrollable android.webkit.WebView focusable focused scrollable
++android.view.View ++android.view.View
++++android.view.View role_description='link' clickable link name='Group Link1' ++++android.view.View role_description='link' clickable link name='Group Link1'
++++++android.widget.TextView name='Group Link1'
++++android.view.View role_description='link' clickable link name='Group Link2' ++++android.view.View role_description='link' clickable link name='Group Link2'
++++++android.widget.TextView name='Group Link2'
android.webkit.WebView focusable focused scrollable android.webkit.WebView focusable focused scrollable
++android.view.View role_description='link' clickable link name='ARIA Link' ++android.view.View role_description='link' clickable link name='ARIA Link'
++++android.widget.TextView name='ARIA Link'
...@@ -2,15 +2,21 @@ android.webkit.WebView focusable focused scrollable ...@@ -2,15 +2,21 @@ android.webkit.WebView focusable focused scrollable
++android.view.View role_description='tree' collection hierarchical item_count=2 row_count=2 ++android.view.View role_description='tree' collection hierarchical item_count=2 row_count=2
++++android.view.View role_description='tree item' checkable clickable collection_item name='Animals' ++++android.view.View role_description='tree item' checkable clickable collection_item name='Animals'
++++++android.view.View role_description='link' clickable focusable link name='Animals' ++++++android.view.View role_description='link' clickable focusable link name='Animals'
++++++++android.widget.TextView name='Animals'
++++++android.view.View ++++++android.view.View
++++++++android.view.View role_description='tree item' clickable collection_item name='Domesticated' ++++++++android.view.View role_description='tree item' clickable collection_item name='Domesticated'
++++++++++android.view.View role_description='link' clickable focusable link name='Domesticated' ++++++++++android.view.View role_description='link' clickable focusable link name='Domesticated'
++++++++++++android.widget.TextView name='Domesticated'
++++++++++android.view.View ++++++++++android.view.View
++++++++++++android.view.View role_description='tree item' checkable checked clickable collection_item name='Dog' ++++++++++++android.view.View role_description='tree item' checkable checked clickable collection_item name='Dog'
++++++++++++++android.view.View role_description='link' clickable focusable link name='Dog' ++++++++++++++android.view.View role_description='link' clickable focusable link name='Dog'
++++++++++++++++android.widget.TextView name='Dog'
++++++++++++android.view.View role_description='tree item' checkable clickable collection_item name='Cat' item_index=1 row_index=1 ++++++++++++android.view.View role_description='tree item' checkable clickable collection_item name='Cat' item_index=1 row_index=1
++++++++++++++android.view.View role_description='link' clickable focusable link name='Cat' ++++++++++++++android.view.View role_description='link' clickable focusable link name='Cat'
++++++++++++++++android.widget.TextView name='Cat'
++++++++android.view.View role_description='tree item' clickable collection_item name='Wild' item_index=1 row_index=1 ++++++++android.view.View role_description='tree item' clickable collection_item name='Wild' item_index=1 row_index=1
++++++++++android.view.View role_description='link' clickable focusable link name='Wild' ++++++++++android.view.View role_description='link' clickable focusable link name='Wild'
++++++++++++android.widget.TextView name='Wild'
++++android.view.View role_description='tree item' clickable collection_item name='Plants' item_index=1 row_index=1 ++++android.view.View role_description='tree item' clickable collection_item name='Plants' item_index=1 row_index=1
++++++android.view.View role_description='link' clickable focusable link name='Plants' ++++++android.view.View role_description='link' clickable focusable link name='Plants'
++++++++android.widget.TextView name='Plants'
android.webkit.WebView focusable focused scrollable android.webkit.WebView focusable focused scrollable
++android.view.View ++android.view.View
++++android.view.View role_description='link' clickable focusable link name='normal link' ++++android.view.View role_description='link' clickable focusable link name='normal link'
++++++android.widget.TextView name='normal link'
android.webkit.WebView focusable focused scrollable android.webkit.WebView focusable focused scrollable
++android.view.View role_description='link' clickable focusable link name='InnerText0' ++android.view.View role_description='link' clickable focusable link name='InnerText0'
++++android.widget.TextView name='InnerText0'
++android.widget.TextView name=' ' ++android.widget.TextView name=' '
++android.view.View role_description='link' clickable focusable link name='InnerText1' hint='Title1' ++android.view.View role_description='link' clickable focusable link name='InnerText1' hint='Title1'
++++android.widget.TextView name='InnerText1'
++android.widget.TextView name=' ' ++android.widget.TextView name=' '
++android.view.View role_description='link' clickable focusable link name='Title2' ++android.view.View role_description='link' clickable focusable link name='Title2'
++++android.widget.TextView name='InnerText2'
++android.widget.TextView name=' ' ++android.widget.TextView name=' '
++android.view.View role_description='link' clickable focusable link name='LabelledBy3' ++android.view.View role_description='link' clickable focusable link name='LabelledBy3'
++++android.widget.TextView name='InnerText3'
++android.view.View role_description='link' clickable focusable link name='Title4' ++android.view.View role_description='link' clickable focusable link name='Title4'
++android.view.View role_description='link' clickable focusable link name='Label5' ++android.view.View role_description='link' clickable focusable link name='Label5'
++android.view.View role_description='link' clickable focusable link name='LabelledBy6' ++android.view.View role_description='link' clickable focusable link name='LabelledBy6'
android.webkit.WebView focusable focused scrollable android.webkit.WebView focusable focused scrollable
++android.view.View clickable name='named anchor' ++android.view.View clickable name='named anchor'
++android.view.View role_description='link' clickable focusable link name='both a named anchor and a link' ++android.view.View role_description='link' clickable focusable link name='both a named anchor and a link'
++++android.widget.TextView name='both a named anchor and a link'
android.webkit.WebView focusable focused scrollable
++android.view.View role_description='link' clickable focusable link name='Header 1 List element 1 List element 2 List element 3'
++++android.view.View role_description='heading 1' heading name='Header 1'
++++android.widget.ListView collection item_count=3 row_count=3
++++++android.view.View collection_item
++++++++android.view.View name='• '
++++++++android.widget.TextView name='List element 1'
++++++android.view.View collection_item item_index=1 row_index=1
++++++++android.view.View name='• '
++++++++android.widget.TextView name='List element 2'
++++++android.view.View collection_item item_index=2 row_index=2
++++++++android.view.View name='• '
++++++++android.widget.TextView name='List element 3'
android.webkit.WebView focusable focused scrollable android.webkit.WebView focusable focused scrollable
++android.view.View ++android.view.View
++++android.view.View role_description='link' clickable focusable link name='dest1' ++++android.view.View role_description='link' clickable focusable link name='dest1'
++++++android.widget.Image role_description='graphic'
++++android.view.View role_description='link' clickable focusable link name='dest2' ++++android.view.View role_description='link' clickable focusable link name='dest2'
++++++android.widget.Image role_description='graphic'
++++android.view.View role_description='link' clickable focusable link name='dest3' ++++android.view.View role_description='link' clickable focusable link name='dest3'
++++++android.widget.Image role_description='graphic'
++++android.view.View role_description='link' clickable focusable link name='dest4' ++++android.view.View role_description='link' clickable focusable link name='dest4'
++++++android.widget.Image role_description='graphic'
++++android.view.View role_description='link' clickable focusable link name='dest5' ++++android.view.View role_description='link' clickable focusable link name='dest5'
++++++android.widget.Image role_description='graphic'
++++android.view.View role_description='link' clickable focusable link name='dest6' ++++android.view.View role_description='link' clickable focusable link name='dest6'
++++++android.widget.Image role_description='graphic'
++++android.view.View role_description='link' clickable focusable link name='dest7' ++++android.view.View role_description='link' clickable focusable link name='dest7'
++++++android.widget.Image role_description='graphic'
++++android.view.View role_description='link' clickable focusable link name='dest.8' ++++android.view.View role_description='link' clickable focusable link name='dest.8'
++++++android.widget.Image role_description='graphic'
++++android.view.View role_description='link' clickable focusable link name='greenbox' ++++android.view.View role_description='link' clickable focusable link name='greenbox'
++++++android.widget.Image role_description='graphic' name='greenbox'
++++android.widget.TextView name=' ' ++++android.widget.TextView name=' '
++++android.view.View role_description='link' clickable focusable link name='greenbox' ++++android.view.View role_description='link' clickable focusable link name='greenbox'
++++++android.widget.Image role_description='graphic' name='greenbox'
android.webkit.WebView focusable focused scrollable android.webkit.WebView focusable focused scrollable
++android.view.View role_description='link' clickable link name='link with no href but onclick' ++android.view.View role_description='link' clickable link name='link with no href but onclick'
++++android.widget.TextView name='link with no href but onclick'
++android.view.View role_description='link' clickable link name='link with no href and click handler added via script' ++android.view.View role_description='link' clickable link name='link with no href and click handler added via script'
++++android.widget.TextView name='link with no href and click handler added via script'
android.webkit.WebView focusable focused scrollable android.webkit.WebView focusable focused scrollable
++android.view.View ++android.view.View
++++android.view.View role_description='link' clickable focusable link name='Link with image at start.' ++++android.view.View role_description='link' clickable focusable link name='Link with image at start.'
++++++android.widget.Image role_description='graphic' name='Link'
++++++android.widget.TextView name=' with image at start.'
++++android.widget.TextView name=' ' ++++android.widget.TextView name=' '
++++android.view.View role_description='link' clickable focusable link name='Link with image in the middle.' ++++android.view.View role_description='link' clickable focusable link name='Link with image in the middle.'
++++++android.widget.TextView name='Link with '
++++++android.widget.Image role_description='graphic' name='image'
++++++android.widget.TextView name=' in the middle.'
++++android.widget.TextView name=' ' ++++android.widget.TextView name=' '
++++android.view.View role_description='link' clickable focusable link name='Link with broken in the middle.' ++++android.view.View role_description='link' clickable focusable link name='Link with broken in the middle.'
++++++android.widget.TextView name='Link with '
++++++android.widget.Image role_description='graphic' name='broken'
++++++android.widget.TextView name=' in the middle.'
++++android.widget.TextView name=' ' ++++android.widget.TextView name=' '
++++android.view.View role_description='link' clickable focusable link name='Link with image at the end' ++++android.view.View role_description='link' clickable focusable link name='Link with image at the end'
++++++android.widget.TextView name='Link with image at the '
++++++android.widget.Image role_description='graphic' name='end'
...@@ -6,3 +6,4 @@ android.webkit.WebView focusable focused has_character_locations scrollable name ...@@ -6,3 +6,4 @@ android.webkit.WebView focusable focused has_character_locations scrollable name
++android.widget.EditText clickable editable_text focusable has_character_locations has_non_empty_value multiline name='Textarea' text_change_added_count=8 ++android.widget.EditText clickable editable_text focusable has_character_locations has_non_empty_value multiline name='Textarea' text_change_added_count=8
++android.widget.Image role_description='graphic' name='Image with alt text' ++android.widget.Image role_description='graphic' name='Image with alt text'
++android.view.View role_description='link' clickable focusable link name='Image inside link' ++android.view.View role_description='link' clickable focusable link name='Image inside link'
++++android.widget.Image role_description='graphic' name='Image inside link'
android.webkit.WebView focusable focused scrollable android.webkit.WebView focusable focused scrollable
++android.view.View ++android.view.View
++++android.view.View role_description='link' clickable focusable link name='unread ' ++++android.view.View role_description='link' clickable focusable link name='unread '
++++++android.widget.TextView name='unread '
++++android.view.View role_description='link' clickable focusable link name='read ' ++++android.view.View role_description='link' clickable focusable link name='read '
++++++android.widget.TextView name='read '
++++android.view.View role_description='link' clickable focusable link name='read ' ++++android.view.View role_description='link' clickable focusable link name='read '
++++++android.widget.TextView name='read '
++++android.view.View role_description='link' clickable focusable link name='read' ++++android.view.View role_description='link' clickable focusable link name='read'
++++++android.widget.Image role_description='graphic' name='read'
++++++android.widget.TextView name='read'
android.webkit.WebView focusable focused scrollable android.webkit.WebView focusable focused scrollable
++android.view.View role_description='link' clickable focusable link name='Empty anchor' ++android.view.View role_description='link' clickable focusable link name='Empty anchor'
++++android.widget.TextView name='Empty anchor'
++android.widget.TextView name=' ' ++android.widget.TextView name=' '
++android.view.View role_description='link' clickable focusable link name='Anchor with content' ++android.view.View role_description='link' clickable focusable link name='Anchor with content'
++++android.widget.TextView name='Anchor with content'
++android.widget.TextView name=' ' ++android.widget.TextView name=' '
++android.view.View role_description='link' clickable focusable link name='Anchor with ID' ++android.view.View role_description='link' clickable focusable link name='Anchor with ID'
++++android.widget.TextView name='Anchor with ID'
++android.widget.TextView name=' ' ++android.widget.TextView name=' '
++android.view.View role_description='link' clickable focusable link name='Empty span' ++android.view.View role_description='link' clickable focusable link name='Empty span'
++++android.widget.TextView name='Empty span'
++android.widget.TextView name=' ' ++android.widget.TextView name=' '
++android.view.View role_description='link' clickable focusable link name='Span with content' ++android.view.View role_description='link' clickable focusable link name='Span with content'
++++android.widget.TextView name='Span with content'
++android.widget.TextView name=' ' ++android.widget.TextView name=' '
++android.view.View role_description='link' clickable focusable link name='Paragraph with content' ++android.view.View role_description='link' clickable focusable link name='Paragraph with content'
++++android.widget.TextView name='Paragraph with content'
++android.view.View ++android.view.View
++++android.view.View clickable ++++android.view.View clickable
++++android.widget.TextView name='After empty anchor' ++++android.widget.TextView name='After empty anchor'
......
android.webkit.WebView focusable focused scrollable android.webkit.WebView focusable focused scrollable
++android.view.View role_description='heading 1 link' clickable heading name='Link In Heading' ++android.view.View role_description='heading 1 link' clickable heading name='Link In Heading'
++++android.view.View role_description='heading 1 link' clickable focusable heading link name='Link In Heading' ++++android.view.View role_description='heading 1 link' clickable focusable heading link name='Link In Heading'
++++++android.widget.TextView heading name='Link In Heading'
...@@ -3,3 +3,4 @@ android.webkit.WebView focusable scrollable ...@@ -3,3 +3,4 @@ android.webkit.WebView focusable scrollable
++android.app.Dialog role_description='dialog' ++android.app.Dialog role_description='dialog'
++++android.widget.TextView name='The dialog subtree should be the only text content in the accessibility tree. ' ++++android.widget.TextView name='The dialog subtree should be the only text content in the accessibility tree. '
++++android.view.View role_description='link' clickable focusable focused link name='Link inside the dialog.' ++++android.view.View role_description='link' clickable focusable focused link name='Link inside the dialog.'
++++++android.widget.TextView name='Link inside the dialog.'
android.webkit.WebView focusable focused scrollable android.webkit.WebView focusable focused scrollable
++android.view.View role_description='navigation' ++android.view.View role_description='navigation'
++++android.view.View role_description='link' clickable focusable link name='Don't click on me' ++++android.view.View role_description='link' clickable focusable link name='Don't click on me'
++++++android.widget.TextView name='Don't click on me'
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment