Commit 81619b38 authored by Dominic Mazzoni's avatar Dominic Mazzoni Committed by Commit Bot

Android accessibility: expose nodes with an image.

Select-to-speak on Android wants to know what nodes in the
accessibility tree contain an image. We can't rely on
exposing this in the class name or role, because sometimes
an image might be inside a button, link, or other leaf-level
UI element. Add a new custom flag
"AccessibilityNodeInfo.hasImage" indicating if it has an image.

BUG=813116

Change-Id: Ia4d3779eecc534ebf997c655a817c5fd06a22d5a
Reviewed-on: https://chromium-review.googlesource.com/923207
Commit-Queue: Dominic Mazzoni <dmazzoni@chromium.org>
Reviewed-by: default avatarKatie Dektar <katie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#537732}
parent e56e2bba
...@@ -23,29 +23,19 @@ namespace content { ...@@ -23,29 +23,19 @@ namespace content {
namespace { namespace {
const char* const BOOL_ATTRIBUTES[] = {"checkable", const char* const BOOL_ATTRIBUTES[] = {
"checked", "checkable", "checked",
"clickable", "clickable", "collection",
"collection", "collection_item", "content_invalid",
"collection_item", "disabled", "dismissable",
"content_invalid", "editable_text", "focusable",
"disabled", "focused", "has_character_locations",
"dismissable", "has_image", "has_non_empty_value",
"editable_text", "heading", "hierarchical",
"focusable", "invisible", "link",
"focused", "multiline", "password",
"has_character_locations", "range", "scrollable",
"has_non_empty_value", "selected", "interesting"};
"heading",
"hierarchical",
"invisible",
"link",
"multiline",
"password",
"range",
"scrollable",
"selected",
"interesting"};
const char* const STRING_ATTRIBUTES[] = { const char* const STRING_ATTRIBUTES[] = {
"name", "hint", "name", "hint",
...@@ -123,6 +113,7 @@ void AccessibilityTreeFormatterAndroid::AddProperties( ...@@ -123,6 +113,7 @@ void AccessibilityTreeFormatterAndroid::AddProperties(
dict->SetBoolean("focused", android_node->IsFocused()); dict->SetBoolean("focused", android_node->IsFocused());
dict->SetBoolean("has_character_locations", dict->SetBoolean("has_character_locations",
android_node->HasCharacterLocations()); android_node->HasCharacterLocations());
dict->SetBoolean("has_image", android_node->HasImage());
dict->SetBoolean("has_non_empty_value", android_node->HasNonEmptyValue()); dict->SetBoolean("has_non_empty_value", android_node->HasNonEmptyValue());
dict->SetBoolean("heading", android_node->IsHeading()); dict->SetBoolean("heading", android_node->IsHeading());
dict->SetBoolean("hierarchical", android_node->IsHierarchical()); dict->SetBoolean("hierarchical", android_node->IsHierarchical());
......
...@@ -1390,6 +1390,18 @@ bool BrowserAccessibilityAndroid::HasCharacterLocations() const { ...@@ -1390,6 +1390,18 @@ bool BrowserAccessibilityAndroid::HasCharacterLocations() const {
return false; return false;
} }
bool BrowserAccessibilityAndroid::HasImage() const {
if (ui::IsImage(GetRole()))
return true;
for (uint32_t i = 0; i < InternalChildCount(); i++) {
BrowserAccessibility* child = InternalGetChild(i);
if (static_cast<BrowserAccessibilityAndroid*>(child)->HasImage())
return true;
}
return false;
}
bool BrowserAccessibilityAndroid::HasOnlyTextChildren() const { bool BrowserAccessibilityAndroid::HasOnlyTextChildren() const {
// This is called from PlatformIsLeaf, so don't call PlatformChildCount // This is called from PlatformIsLeaf, so don't call PlatformChildCount
// from within this! // from within this!
......
...@@ -74,6 +74,7 @@ class CONTENT_EXPORT BrowserAccessibilityAndroid : public BrowserAccessibility { ...@@ -74,6 +74,7 @@ class CONTENT_EXPORT BrowserAccessibilityAndroid : public BrowserAccessibility {
bool HasNonEmptyValue() const; bool HasNonEmptyValue() const;
bool HasCharacterLocations() const; bool HasCharacterLocations() const;
bool HasImage() const;
const char* GetClassName() const; const char* GetClassName() const;
base::string16 GetText() const override; base::string16 GetText() const override;
......
...@@ -247,6 +247,7 @@ void DumpAccessibilityTreeTest::AddDefaultFilters( ...@@ -247,6 +247,7 @@ void DumpAccessibilityTreeTest::AddDefaultFilters(
AddFilter(filters, "hint=*"); AddFilter(filters, "hint=*");
AddFilter(filters, "interesting", Filter::DENY); AddFilter(filters, "interesting", Filter::DENY);
AddFilter(filters, "has_character_locations", Filter::DENY); AddFilter(filters, "has_character_locations", Filter::DENY);
AddFilter(filters, "has_image", Filter::DENY);
// //
// General // General
......
...@@ -710,7 +710,8 @@ jboolean WebContentsAccessibilityAndroid::PopulateAccessibilityNodeInfo( ...@@ -710,7 +710,8 @@ jboolean WebContentsAccessibilityAndroid::PopulateAccessibilityNodeInfo(
base::android::ConvertUTF16ToJavaString(env, node->GetRoleDescription()), base::android::ConvertUTF16ToJavaString(env, node->GetRoleDescription()),
base::android::ConvertUTF16ToJavaString(env, node->GetHint()), base::android::ConvertUTF16ToJavaString(env, node->GetHint()),
node->GetIntAttribute(ax::mojom::IntAttribute::kTextSelStart), node->GetIntAttribute(ax::mojom::IntAttribute::kTextSelStart),
node->GetIntAttribute(ax::mojom::IntAttribute::kTextSelEnd)); node->GetIntAttribute(ax::mojom::IntAttribute::kTextSelEnd),
node->HasImage());
Java_WebContentsAccessibilityImpl_setAccessibilityNodeInfoLollipopAttributes( Java_WebContentsAccessibilityImpl_setAccessibilityNodeInfoLollipopAttributes(
env, obj, info, node->CanOpenPopup(), node->IsContentInvalid(), env, obj, info, node->CanOpenPopup(), node->IsContentInvalid(),
......
...@@ -34,11 +34,12 @@ public class KitKatWebContentsAccessibility extends WebContentsAccessibilityImpl ...@@ -34,11 +34,12 @@ public class KitKatWebContentsAccessibility extends WebContentsAccessibilityImpl
@Override @Override
protected void setAccessibilityNodeInfoKitKatAttributes(AccessibilityNodeInfo node, protected void setAccessibilityNodeInfoKitKatAttributes(AccessibilityNodeInfo node,
boolean isRoot, boolean isEditableText, String role, String roleDescription, boolean isRoot, boolean isEditableText, String role, String roleDescription,
String hint, int selectionStartIndex, int selectionEndIndex) { String hint, int selectionStartIndex, int selectionEndIndex, boolean hasImage) {
Bundle bundle = node.getExtras(); Bundle bundle = node.getExtras();
bundle.putCharSequence("AccessibilityNodeInfo.chromeRole", role); bundle.putCharSequence("AccessibilityNodeInfo.chromeRole", role);
bundle.putCharSequence("AccessibilityNodeInfo.roleDescription", roleDescription); bundle.putCharSequence("AccessibilityNodeInfo.roleDescription", roleDescription);
bundle.putCharSequence("AccessibilityNodeInfo.hint", hint); bundle.putCharSequence("AccessibilityNodeInfo.hint", hint);
if (hasImage) bundle.putCharSequence("AccessibilityNodeInfo.hasImage", "true");
if (isRoot) { if (isRoot) {
bundle.putCharSequence( bundle.putCharSequence(
"ACTION_ARGUMENT_HTML_ELEMENT_STRING_VALUES", mSupportedHtmlElementTypes); "ACTION_ARGUMENT_HTML_ELEMENT_STRING_VALUES", mSupportedHtmlElementTypes);
......
...@@ -41,9 +41,9 @@ public class OWebContentsAccessibility extends LollipopWebContentsAccessibility ...@@ -41,9 +41,9 @@ public class OWebContentsAccessibility extends LollipopWebContentsAccessibility
@Override @Override
protected void setAccessibilityNodeInfoKitKatAttributes(AccessibilityNodeInfo node, protected void setAccessibilityNodeInfoKitKatAttributes(AccessibilityNodeInfo node,
boolean isRoot, boolean isEditableText, String role, String roleDescription, boolean isRoot, boolean isEditableText, String role, String roleDescription,
String hint, int selectionStartIndex, int selectionEndIndex) { String hint, int selectionStartIndex, int selectionEndIndex, boolean hasImage) {
super.setAccessibilityNodeInfoKitKatAttributes(node, isRoot, isEditableText, role, super.setAccessibilityNodeInfoKitKatAttributes(node, isRoot, isEditableText, role,
roleDescription, hint, selectionStartIndex, selectionEndIndex); roleDescription, hint, selectionStartIndex, selectionEndIndex, hasImage);
node.setHintText(hint); node.setHintText(hint);
} }
......
...@@ -1221,7 +1221,7 @@ public class WebContentsAccessibilityImpl extends AccessibilityNodeProvider ...@@ -1221,7 +1221,7 @@ public class WebContentsAccessibilityImpl extends AccessibilityNodeProvider
@CalledByNative @CalledByNative
protected void setAccessibilityNodeInfoKitKatAttributes(AccessibilityNodeInfo node, protected void setAccessibilityNodeInfoKitKatAttributes(AccessibilityNodeInfo node,
boolean isRoot, boolean isEditableText, String role, String roleDescription, boolean isRoot, boolean isEditableText, String role, String roleDescription,
String hint, int selectionStartIndex, int selectionEndIndex) { String hint, int selectionStartIndex, int selectionEndIndex, boolean hasImage) {
// Requires KitKat or higher. // Requires KitKat or higher.
} }
......
android.webkit.WebView focusable focused scrollable android.webkit.WebView focusable focused has_image scrollable
++android.view.View ++android.view.View has_image
++++android.widget.Image role_description='graphic' name='pipe' ++++android.widget.Image role_description='graphic' has_image name='pipe'
++++android.view.View name=' ' ++++android.view.View name=' '
++++android.widget.Image role_description='graphic' ++++android.widget.Image role_description='graphic' has_image
++++android.view.View name=' ' ++++android.view.View name=' '
++++android.widget.Image role_description='graphic' name=' ' ++++android.widget.Image role_description='graphic' has_image name=' '
\ No newline at end of file
<!-- <!--
@MAC-ALLOW:AXRoleDescription='image' @MAC-ALLOW:AXRoleDescription='image'
@WIN-ALLOW:xml-roles:* @WIN-ALLOW:xml-roles:*
@ANDROID-ALLOW:has_image
--> -->
<html> <html>
<body> <body>
......
...@@ -157,4 +157,17 @@ bool IsMenuRelated(ax::mojom::Role role) { ...@@ -157,4 +157,17 @@ bool IsMenuRelated(ax::mojom::Role role) {
} }
} }
bool IsImage(ax::mojom::Role role) {
switch (role) {
case ax::mojom::Role::kCanvas:
case ax::mojom::Role::kImageMap:
case ax::mojom::Role::kImage:
case ax::mojom::Role::kSvgRoot:
case ax::mojom::Role::kVideo:
return true;
default:
return false;
}
}
} // namespace ui } // namespace ui
...@@ -35,6 +35,9 @@ AX_EXPORT bool IsControl(ax::mojom::Role role); ...@@ -35,6 +35,9 @@ AX_EXPORT bool IsControl(ax::mojom::Role role);
// Returns true if this node is a menu or related role. // Returns true if this node is a menu or related role.
AX_EXPORT bool IsMenuRelated(ax::mojom::Role role); AX_EXPORT bool IsMenuRelated(ax::mojom::Role role);
// Returns true if it's an image, graphic, canvas, etc.
AX_EXPORT bool IsImage(ax::mojom::Role role);
} // namespace ui } // namespace ui
#endif // UI_ACCESSIBILITY_AX_ROLE_PROPERTIES_H_ #endif // UI_ACCESSIBILITY_AX_ROLE_PROPERTIES_H_
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