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

Update Android to concat a11y state descriptions

This CL updates our approach to the state description
member variable of AccessibilityNodeInfo objects on Android.
Until now we have picked a single state description based
on the node. With this change we now concatenate all
potential state descriptions to make sure no information is
lost on mixed nodes (e.g. multiselectable listBox).

We added a few exceptions to concatenation, namely the case
of a multiselectable listbox will not announce the number of
items in the list when some are selected. This is to prevent
an utterance like:

"multiselectable, 2 of 4 selected. 4 items"

Instead in the case of a multiselectable listbox, it will be
read as either:

"multiselectable, none selected. 4 items"
or
"multiselectable, 2 of 4 selected."

Similarly, we make toggle buttons and partially checked
checkboxes mutually exclusive to prevent double speak.

As of now all other cases are simply concatenated.


AX-Relnotes: N/A
Change-Id: I5650230b141cae24dfd935be596fb14720b723ec
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2476520Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Reviewed-by: default avatarMark Schillaci <mschillaci@google.com>
Commit-Queue: Mark Schillaci <mschillaci@google.com>
Cr-Commit-Position: refs/heads/master@{#818000}
parent fd9ef5ac
......@@ -549,30 +549,37 @@ base::string16 BrowserAccessibilityAndroid::GetHint() const {
}
base::string16 BrowserAccessibilityAndroid::GetStateDescription() const {
std::vector<base::string16> state_descs;
// For multiselectable state, generate a state description. We do not set a
// state description for pop up/<select> to prevent double utterances.
if (IsMultiselectable() && GetRole() != ax::mojom::Role::kPopUpButton)
return GetMultiselectableStateDescription();
// For Toggle buttons, we will append "on"/"off" in the state description.
if (GetRole() == ax::mojom::Role::kToggleButton)
return GetToggleButtonStateDescription();
state_descs.push_back(GetMultiselectableStateDescription());
// For Checkboxes, if we are in a kMixed state, we will communicate
// "partially checked" through the state description.
if (IsCheckable() && !IsReportingCheckable())
return GetCheckboxStateDescription();
// "partially checked" through the state description. This is mutually
// exclusive with the on/off of toggle buttons below.
if (IsCheckable() && !IsReportingCheckable()) {
state_descs.push_back(GetCheckboxStateDescription());
} else if (GetRole() == ax::mojom::Role::kToggleButton) {
// For Toggle buttons, we will append "on"/"off" in the state description.
state_descs.push_back(GetToggleButtonStateDescription());
}
// For list boxes, use state description to communicate child item count.
if (GetRole() == ax::mojom::Role::kListBox)
return GetListBoxStateDescription();
// For list boxes, use state description to communicate child item count. We
// will not communicate this in the case that the listbox is also
// multiselectable and has some items selected, since the same info would be
// communicated as "x of y selected".
if (GetRole() == ax::mojom::Role::kListBox &&
(!IsMultiselectable() || !GetSelectedItemCount()))
state_descs.push_back(GetListBoxStateDescription());
// For list box items, use state description to communicate index of item.
if (GetRole() == ax::mojom::Role::kListBoxOption)
return GetListBoxItemStateDescription();
state_descs.push_back(GetListBoxItemStateDescription());
// Otherwise we will not use state description
return base::string16();
// Concatenate all state descriptions and return.
return base::JoinString(state_descs, base::ASCIIToUTF16(" "));
}
base::string16 BrowserAccessibilityAndroid::GetMultiselectableStateDescription()
......@@ -1315,6 +1322,20 @@ int BrowserAccessibilityAndroid::GetItemCount() const {
return count;
}
int BrowserAccessibilityAndroid::GetSelectedItemCount() const {
// Count the number of selected children.
int selected_count = 0;
for (PlatformChildIterator it = PlatformChildrenBegin();
it != PlatformChildrenEnd(); ++it) {
BrowserAccessibilityAndroid* child =
static_cast<BrowserAccessibilityAndroid*>(it.get());
if (child->IsSelected())
selected_count++;
}
return selected_count;
}
bool BrowserAccessibilityAndroid::CanScrollForward() const {
if (IsSlider()) {
// If it's not a native INPUT element, then increment and decrement
......
......@@ -101,6 +101,7 @@ class CONTENT_EXPORT BrowserAccessibilityAndroid : public BrowserAccessibility {
int GetItemIndex() const;
int GetItemCount() const;
int GetSelectedItemCount() const;
bool CanScrollForward() const;
bool CanScrollBackward() const;
......
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.widget.ListView role_description='list box' clickable collection focusable multiselectable name='My Listbox' state_description='multiselectable, none selected. 4 items' item_count=4 row_count=4
++++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
......
......@@ -2,4 +2,4 @@ android.webkit.WebView focusable focused scrollable
++android.widget.Button role_description='button' clickable focusable name='Regular button'
++android.widget.ToggleButton role_description='toggle button' checkable clickable focusable name='Toggle button unpressed' state_description='Off'
++android.widget.ToggleButton role_description='toggle button' checkable checked clickable focusable name='Toggle button pressed' state_description='On'
++android.widget.ToggleButton role_description='toggle button' checkable clickable focusable name='Toggle button mixed' state_description='Off'
\ No newline at end of file
++android.widget.ToggleButton role_description='toggle button' checkable clickable focusable name='Toggle button mixed' state_description='Partially Checked'
\ No newline at end of file
......@@ -2,4 +2,4 @@ android.webkit.WebView focusable focused scrollable
++android.widget.Button role_description='button' clickable focusable name='Regular button'
++android.widget.ToggleButton role_description='toggle button' checkable clickable focusable name='Toggle button' state_description='Off'
++android.widget.ToggleButton role_description='toggle button' checkable checked clickable focusable name='Toggle button' state_description='On'
++android.widget.ToggleButton role_description='toggle button' checkable clickable focusable name='Toggle button' state_description='Off'
\ No newline at end of file
++android.widget.ToggleButton role_description='toggle button' checkable clickable focusable name='Toggle button' state_description='Partially Checked'
\ 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