Commit 529872b7 authored by Mark Schillaci's avatar Mark Schillaci Committed by Commit Bot

Added a11y state description to ListBox on Android

This CL updates the behavior of ListBox on Android.

With this change, the state of a Listbox ("x items") will
now be read during swipe navigation when a node is initially
selected. For ListBoxItem, the state of the item will read
as "in list, item x of y".

We append the state of the ListBox or items in the
stateDescription element of the node's corresponding
AccessibilityNodeInfo object.

This CL also updates associated unit test expectations.

AX-Relnoates: ListBoxes and ListBoxItems now explicitly announce their count and item index.
Bug: 1101656
Change-Id: Ibdae3a0401f03cde373d4055dbc93f9465bb2f69
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2462276Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarMark Schillaci <mschillaci@google.com>
Reviewed-by: default avatardanakj <danakj@chromium.org>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Commit-Queue: Mark Schillaci <mschillaci@google.com>
Cr-Commit-Position: refs/heads/master@{#816359}
parent 5d4c8ba2
......@@ -570,6 +570,14 @@ base::string16 BrowserAccessibilityAndroid::GetStateDescription() const {
if (IsCheckable() && !IsReportingCheckable())
return GetCheckboxStateDescription();
// For list boxes, use state description to communicate child item count.
if (GetRole() == ax::mojom::Role::kListBox)
return GetListBoxStateDescription();
// For list box items, use state description to communicate index of item.
if (GetRole() == ax::mojom::Role::kListBoxOption)
return GetListBoxItemStateDescription();
// Otherwise we will not use state description
return base::string16();
}
......@@ -624,6 +632,44 @@ base::string16 BrowserAccessibilityAndroid::GetCheckboxStateDescription()
return content_client->GetLocalizedString(IDS_AX_CHECKBOX_PARTIALLY_CHECKED);
}
base::string16 BrowserAccessibilityAndroid::GetListBoxStateDescription() const {
content::ContentClient* content_client = content::GetContentClient();
// For empty list boxes, we will return an empty string.
int item_count = GetItemCount();
if (!item_count)
return base::string16();
// Otherwise, we will communicate "x items" as the state description.
return base::ReplaceStringPlaceholders(
content_client->GetLocalizedString(IDS_AX_LIST_BOX_STATE_DESCRIPTION),
base::NumberToString16(item_count), nullptr);
}
base::string16 BrowserAccessibilityAndroid::GetListBoxItemStateDescription()
const {
content::ContentClient* content_client = content::GetContentClient();
BrowserAccessibilityAndroid* parent =
static_cast<BrowserAccessibilityAndroid*>(PlatformGetParent());
// If we cannot find the parent collection, escape with an empty string.
if (!parent)
return base::string16();
// For list box items, we will communicate "in list, item x of y". We add
// one (1) to our index to offset from counting at 0.
int item_index = GetItemIndex() + 1;
int item_count = parent->GetItemCount();
return base::ReplaceStringPlaceholders(
content_client->GetLocalizedString(
IDS_AX_LIST_BOX_ITEM_STATE_DESCRIPTION),
std::vector<base::string16>({base::NumberToString16(item_index),
base::NumberToString16(item_count)}),
nullptr);
}
std::string BrowserAccessibilityAndroid::GetRoleString() const {
return ui::ToString(GetRole());
}
......
......@@ -95,6 +95,8 @@ class CONTENT_EXPORT BrowserAccessibilityAndroid : public BrowserAccessibility {
base::string16 GetMultiselectableStateDescription() const;
base::string16 GetToggleButtonStateDescription() const;
base::string16 GetCheckboxStateDescription() const;
base::string16 GetListBoxStateDescription() const;
base::string16 GetListBoxItemStateDescription() const;
base::string16 GetRoleDescription() const;
......
......@@ -11,6 +11,7 @@
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
#include "content/public/browser/accessibility_tree_formatter.h"
#include "content/public/common/content_switches.h"
......@@ -136,6 +137,10 @@ bool DumpAccessibilityTestHelper::ValidateAgainstExpectation(
base::JoinString(actual_lines, "\n") + "\n";
CHECK(base::WriteFile(expected_file, actual_contents_for_output));
LOG(INFO) << "Wrote expectations to: " << expected_file.LossyDisplayName();
#if defined(OS_ANDROID)
LOG(INFO) << "Generated expectations written to file on test device.";
LOG(INFO) << "To fetch, run: adb pull " << expected_file.LossyDisplayName();
#endif
}
return !is_different;
......
android.webkit.WebView focusable focused scrollable
++android.view.View name='Choose a fruit, with text content'
++android.widget.Spinner clickable focusable name='Choose a fruit, with text content'
++android.widget.ListView role_description='list box' clickable collection item_count=3 row_count=3
++++android.view.View clickable collection_item focusable selected name='Apple'
++++android.view.View clickable collection_item focusable name='Banana' item_index=1 row_index=1
++++android.view.View clickable collection_item focusable name='Cherry' item_index=2 row_index=2
\ No newline at end of file
++android.widget.ListView role_description='list box' clickable collection state_description='3 items' item_count=3 row_count=3
++++android.view.View clickable collection_item focusable selected name='Apple' state_description='in list, item 1 of 3'
++++android.view.View clickable collection_item focusable name='Banana' state_description='in list, item 2 of 3' item_index=1 row_index=1
++++android.view.View clickable collection_item focusable name='Cherry' state_description='in list, item 3 of 3' item_index=2 row_index=2
\ No newline at end of file
android.webkit.WebView focusable focused scrollable
++android.view.View role_description='heading 1' heading name='Start of test: striped should have selected state'
++android.widget.ListView role_description='list box' clickable collection disabled item_count=4 row_count=4
++++android.view.View clickable collection_item disabled focusable name='Orange'
++++android.view.View clickable collection_item disabled focusable selected name='Striped' item_index=1 row_index=1
++++android.view.View clickable collection_item disabled focusable name='Calico' item_index=2 row_index=2
++++android.view.View clickable collection_item disabled focusable name='Black' item_index=3 row_index=3
++android.widget.ListView role_description='list box' clickable collection disabled state_description='4 items' item_count=4 row_count=4
++++android.view.View clickable collection_item disabled focusable name='Orange' state_description='in list, item 1 of 4'
++++android.view.View clickable collection_item disabled focusable selected name='Striped' state_description='in list, item 2 of 4' item_index=1 row_index=1
++++android.view.View clickable collection_item disabled focusable name='Calico' state_description='in list, item 3 of 4' item_index=2 row_index=2
++++android.view.View clickable collection_item disabled focusable name='Black' state_description='in list, item 4 of 4' item_index=3 row_index=3
++android.view.View name='End of test'
\ No newline at end of file
android.webkit.WebView focusable focused scrollable
++android.widget.ListView role_description='list box' clickable collection item_count=4 row_count=4
++++android.view.View clickable collection_item focusable name='Item 1'
++++android.view.View clickable collection_item focusable name='Item 2' item_index=1 row_index=1
++android.widget.ListView role_description='list box' clickable collection state_description='4 items' item_count=4 row_count=4
++++android.view.View clickable collection_item focusable name='Item 1' state_description='in list, item 1 of 4'
++++android.view.View clickable collection_item focusable name='Item 2' state_description='in list, item 2 of 4' item_index=1 row_index=1
++++android.view.View role_description='splitter'
++++android.view.View clickable collection_item focusable name='Second group item 1' item_index=2 row_index=2
++++android.view.View clickable collection_item focusable name='Second group item 2' item_index=3 row_index=3
++++android.view.View clickable collection_item focusable name='Second group item 1' state_description='in list, item 3 of 4' item_index=2 row_index=2
++++android.view.View clickable collection_item focusable name='Second group item 2' state_description='in list, item 4 of 4' item_index=3 row_index=3
\ No newline at end of file
android.webkit.WebView focusable focused scrollable
++android.widget.ListView role_description='list box' clickable collection focusable multiselectable name='My Listbox' state_description='multiselectable, none selected.' item_count=4 row_count=4
++++android.view.View clickable collection_item focusable name='Example 1'
++++android.view.View clickable collection_item focusable name='Example 2' item_index=1 row_index=1
++++android.view.View clickable collection_item focusable name='Example 3' item_index=2 row_index=2
++++android.view.View clickable collection_item focusable name='Example 4' item_index=3 row_index=3
++++android.view.View clickable collection_item focusable name='Example 1' state_description='in list, item 1 of 4'
++++android.view.View clickable collection_item focusable name='Example 2' state_description='in list, item 2 of 4' item_index=1 row_index=1
++++android.view.View clickable collection_item focusable name='Example 3' state_description='in list, item 3 of 4' item_index=2 row_index=2
++++android.view.View clickable collection_item focusable name='Example 4' state_description='in list, item 4 of 4' item_index=3 row_index=3
++android.widget.ListView role_description='list box' clickable collection focusable multiselectable name='My Listbox' state_description='multiselectable, 2 of 4 selected.' item_count=4 row_count=4
++++android.view.View clickable collection_item focusable name='Example 1'
++++android.view.View clickable collection_item focusable selected name='Example 2' item_index=1 row_index=1
++++android.view.View clickable collection_item focusable name='Example 3' item_index=2 row_index=2
++++android.view.View clickable collection_item focusable selected name='Example 4' item_index=3 row_index=3
\ No newline at end of file
++++android.view.View clickable collection_item focusable name='Example 1' state_description='in list, item 1 of 4'
++++android.view.View clickable collection_item focusable selected name='Example 2' state_description='in list, item 2 of 4' item_index=1 row_index=1
++++android.view.View clickable collection_item focusable name='Example 3' state_description='in list, item 3 of 4' item_index=2 row_index=2
++++android.view.View clickable collection_item focusable selected name='Example 4' state_description='in list, item 4 of 4' item_index=3 row_index=3
\ No newline at end of file
android.webkit.WebView focusable focused scrollable
++android.widget.ListView role_description='list box' clickable collection item_count=4 row_count=4
++++android.view.View clickable collection_item focusable name='option 1'
++++android.view.View clickable collection_item focusable name='label 2' item_index=1 row_index=1
++++android.view.View clickable collection_item focusable name='caterpillar' item_index=2 row_index=2
++++android.view.View clickable collection_item focusable name='catfish' item_index=3 row_index=3
++android.widget.ListView role_description='list box' clickable collection state_description='4 items' item_count=4 row_count=4
++++android.view.View clickable collection_item focusable name='option 1' state_description='in list, item 1 of 4'
++++android.view.View clickable collection_item focusable name='label 2' state_description='in list, item 2 of 4' item_index=1 row_index=1
++++android.view.View clickable collection_item focusable name='caterpillar' state_description='in list, item 3 of 4' item_index=2 row_index=2
++++android.view.View clickable collection_item focusable name='catfish' state_description='in list, item 4 of 4' item_index=3 row_index=3
\ No newline at end of file
android.webkit.WebView focusable focused scrollable
++android.view.View role_description='article' name='This is an ARIA article 1.'
++android.view.View role_description='article' name='This is an ARIA article 2.'
++android.widget.ListView role_description='list box' clickable collection item_count=2 row_count=2
++++android.view.View clickable collection_item focusable name='Item 1'
++++android.view.View clickable collection_item focusable name='Item 2' item_index=1 row_index=1
++android.widget.ListView role_description='list box' clickable collection item_count=2 row_count=2
++++android.view.View clickable collection_item focusable name='Item 1'
++++android.view.View clickable collection_item focusable name='Item 2' item_index=1 row_index=1
++android.widget.ListView role_description='list box' clickable collection state_description='2 items' item_count=2 row_count=2
++++android.view.View clickable collection_item focusable name='Item 1' state_description='in list, item 1 of 2'
++++android.view.View clickable collection_item focusable name='Item 2' state_description='in list, item 2 of 2' item_index=1 row_index=1
++android.widget.ListView role_description='list box' clickable collection state_description='2 items' item_count=2 row_count=2
++++android.view.View clickable collection_item focusable name='Item 1' state_description='in list, item 1 of 2'
++++android.view.View clickable collection_item focusable name='Item 2' state_description='in list, item 2 of 2' item_index=1 row_index=1
++android.view.View
++++android.widget.RadioButton role_description='radio button' checkable clickable focusable item_index=2 row_index=2
++++android.widget.TextView name='1'
......
android.webkit.WebView focusable focused scrollable
++android.widget.ListView role_description='list box' clickable collection item_count=2 row_count=2
++++android.view.View clickable collection_item focusable selected name='1'
++++android.view.View clickable collection_item focusable name='2' item_index=1 row_index=1
\ No newline at end of file
++android.widget.ListView role_description='list box' clickable collection state_description='2 items' item_count=2 row_count=2
++++android.view.View clickable collection_item focusable selected name='1' state_description='in list, item 1 of 2'
++++android.view.View clickable collection_item focusable name='2' state_description='in list, item 2 of 2' item_index=1 row_index=1
\ No newline at end of file
android.webkit.WebView focusable focused scrollable
++android.widget.ListView role_description='list box' clickable collection item_count=4 row_count=4
++++android.view.View clickable collection_item focusable name='Item 1'
++++android.view.View clickable collection_item focusable name='Item 2' item_index=1 row_index=1
++++android.view.View clickable collection_item focusable name='Item 3' item_index=2 row_index=2
++++android.view.View clickable collection_item focusable name='Item 4' item_index=3 row_index=3
++android.widget.ListView role_description='list box' clickable collection item_count=5 row_count=5
++++android.view.View clickable collection_item focusable name='Item 1'
++++android.view.View clickable collection_item focusable name='Item 2' item_index=1 row_index=1
++++android.view.View clickable collection_item focusable name='Item 3' item_index=2 row_index=2
++++android.view.View clickable collection_item focusable name='Item 4' item_index=3 row_index=3
++++android.view.View clickable collection_item focusable name='Item 5' item_index=4 row_index=4
\ No newline at end of file
++android.widget.ListView role_description='list box' clickable collection state_description='4 items' item_count=4 row_count=4
++++android.view.View clickable collection_item focusable name='Item 1' state_description='in list, item 1 of 4'
++++android.view.View clickable collection_item focusable name='Item 2' state_description='in list, item 2 of 4' item_index=1 row_index=1
++++android.view.View clickable collection_item focusable name='Item 3' state_description='in list, item 3 of 4' item_index=2 row_index=2
++++android.view.View clickable collection_item focusable name='Item 4' state_description='in list, item 4 of 4' item_index=3 row_index=3
++android.widget.ListView role_description='list box' clickable collection state_description='5 items' item_count=5 row_count=5
++++android.view.View clickable collection_item focusable name='Item 1' state_description='in list, item 1 of 5'
++++android.view.View clickable collection_item focusable name='Item 2' state_description='in list, item 2 of 5' item_index=1 row_index=1
++++android.view.View clickable collection_item focusable name='Item 3' state_description='in list, item 3 of 5' item_index=2 row_index=2
++++android.view.View clickable collection_item focusable name='Item 4' state_description='in list, item 4 of 5' item_index=3 row_index=3
++++android.view.View clickable collection_item focusable name='Item 5' state_description='in list, item 5 of 5' item_index=4 row_index=4
\ No newline at end of file
......@@ -2,7 +2,7 @@ android.webkit.WebView focusable focused scrollable
++android.view.View
++++android.view.View name='Choose one:'
++++android.widget.Spinner role_description='pop up button' clickable focusable name='Choose one: Foo'
++++android.widget.ListView role_description='list box' clickable collection focusable name='Choose one:' item_count=3 row_count=3
++++++android.view.View clickable collection_item focusable name='Baz'
++++++android.view.View clickable collection_item focusable name='Bar' item_index=1 row_index=1
++++++android.view.View clickable collection_item focusable name='Foo' item_index=2 row_index=2
++++android.widget.ListView role_description='list box' clickable collection focusable name='Choose one:' state_description='3 items' item_count=3 row_count=3
++++++android.view.View clickable collection_item focusable name='Baz' state_description='in list, item 1 of 3'
++++++android.view.View clickable collection_item focusable name='Bar' state_description='in list, item 2 of 3' item_index=1 row_index=1
++++++android.view.View clickable collection_item focusable name='Foo' state_description='in list, item 3 of 3' item_index=2 row_index=2
\ No newline at end of file
......@@ -182,6 +182,14 @@ For more information, see the detailed help with:
out/Debug/content_browsertests --gtest_help
```
Note: For Android, generated expectations will replace the existing files on
the test device. For example, if running on an emulator, for an ARIA test
called `my-test.html`, the generated output can be found:
```
/storage/emulated/0/chromium_tests_root/content/test/
data/accessibility/aria/my-test-expected-android.txt
```
## Adding a new test:
If you are adding a new test file remember to add a corresponding test case in:
......
......@@ -799,6 +799,12 @@ below:
<message name="IDS_AX_CHECKBOX_PARTIALLY_CHECKED" desc="Accessibility state description for a checkbox that is in the partially checked state">
Partially Checked
</message>
<message name="IDS_AX_LIST_BOX_STATE_DESCRIPTION" desc="Accessibility state description for a list box of items">
<ph name="COUNT">$1<ex>3</ex></ph> items
</message>
<message name="IDS_AX_LIST_BOX_ITEM_STATE_DESCRIPTION" desc="Accessibility state description for an item that is part of a list box">
in list, item <ph name="INDEX">$1<ex>1</ex></ph> of <ph name="COUNT">$2<ex>3</ex></ph>
</message>
</if>
<!-- Automatic image annotations for accessibility -->
......
5e7e6ff99f7cb86524aba3dd7cb307a29e82b886
\ No newline at end of file
988bf891873b693e8ce4a638eae73df2e1adfd57
\ No newline at end of file
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