Commit be36800c authored by Hiroki Sato's avatar Hiroki Sato Committed by Commit Bot

Prevent announcing hint text twice.

Android TextView populates the text with hint text if the text is empty.
This invokes ChromeVox reads hint text twice.

This CL uses SHOWING_HINT_TEXT value to prevent it.

Bug: b/151060876
Test: unit_tests --gtest_filter="AXTreeSourceArcTest.*"
Test: manual. talkback test app "Text Fields" section.
Change-Id: I273907edf8a6d62558fe3af09819daac560a65fa
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2094422
Commit-Queue: Hiroki Sato <hirokisato@chromium.org>
Reviewed-by: default avatarDavid Tseng <dtseng@chromium.org>
Reviewed-by: default avatarSara Kato <sarakato@chromium.org>
Cr-Commit-Position: refs/heads/master@{#749469}
parent e83f522c
...@@ -331,7 +331,11 @@ void AccessibilityNodeInfoDataWrapper::Serialize( ...@@ -331,7 +331,11 @@ void AccessibilityNodeInfoDataWrapper::Serialize(
// This ensures that the edited text will be read out appropriately. // This ensures that the edited text will be read out appropriately.
if (!text.empty()) { if (!text.empty()) {
if (out_data->role == ax::mojom::Role::kTextField) { if (out_data->role == ax::mojom::Role::kTextField) {
out_data->SetValue(text); // When the edited text is empty, Android framework shows |hint_text| in
// the text field and |text| is also populated with |hint_text|.
// Prevent the duplicated output of |hint_text|.
if (!GetProperty(AXBooleanProperty::SHOWING_HINT_TEXT))
out_data->SetValue(text);
} else { } else {
names.push_back(text); names.push_back(text);
} }
......
...@@ -540,60 +540,85 @@ TEST_F(AXTreeSourceArcTest, AccessibleNameComputationTextField) { ...@@ -540,60 +540,85 @@ TEST_F(AXTreeSourceArcTest, AccessibleNameComputationTextField) {
root_window->root_node_id = 1; root_window->root_node_id = 1;
std::unique_ptr<ui::AXNodeData> data; std::unique_ptr<ui::AXNodeData> data;
SetProperty(root, AXStringProperty::CLASS_NAME, ""); SetProperty(root, AXBooleanProperty::EDITABLE, true);
// Populate the tree source with the data. // Populate the tree source with the data.
CallNotifyAccessibilityEvent(event.get()); CallNotifyAccessibilityEvent(event.get());
// Case for when both text property and content_description is non-empty. struct AndroidState {
SetProperty(root, AXBooleanProperty::EDITABLE, true); std::string content_description, text, hint_text;
SetProperty(root, AXStringProperty::TEXT, "foo@example.com"); bool showingHint = false;
SetProperty(root, AXStringProperty::CONTENT_DESCRIPTION, };
"Type your email here."); struct ChromeState {
std::string name, value;
CallSerializeNode(root, &data); };
std::string prop;
ASSERT_TRUE(
data->GetStringAttribute(ax::mojom::StringAttribute::kName, &prop));
EXPECT_EQ("Type your email here.", prop);
ASSERT_TRUE(
data->GetStringAttribute(ax::mojom::StringAttribute::kValue, &prop));
EXPECT_EQ("foo@example.com", prop);
// Case for when text property is empty.
SetProperty(root, AXStringProperty::TEXT, "");
SetProperty(root, AXStringProperty::CONTENT_DESCRIPTION,
"Type your email here.");
CallSerializeNode(root, &data);
ASSERT_TRUE(
data->GetStringAttribute(ax::mojom::StringAttribute::kName, &prop));
EXPECT_EQ("Type your email here.", prop);
ASSERT_FALSE(
data->GetStringAttribute(ax::mojom::StringAttribute::kValue, &prop));
// Case for when only text property is non-empty.
SetProperty(root, AXStringProperty::TEXT, "foo@example.com");
SetProperty(root, AXStringProperty::CONTENT_DESCRIPTION, "");
CallSerializeNode(root, &data);
ASSERT_FALSE( std::vector<std::pair<AndroidState, ChromeState>> test_cases = {
data->GetStringAttribute(ax::mojom::StringAttribute::kName, &prop)); {
ASSERT_TRUE( {"email", "editing_text", "", false},
data->GetStringAttribute(ax::mojom::StringAttribute::kValue, &prop)); {"email", "editing_text"},
EXPECT_EQ("foo@example.com", prop); },
{
{"email", "", "", false},
{"email", ""},
},
{
{"", "editing_text", "", false},
{"", "editing_text"},
},
{
// User input and hint text.
{"", "editing_text", "hint@example.com", false},
{"hint@example.com", "editing_text"},
},
{
// No user input. Hint text is non-empty.
{"", "hint@example.com", "hint@example.com", true},
{"hint@example.com", ""},
},
{
// User input is the same as hint text.
{"", "example@example.com", "example@example.com", false},
{"example@example.com", "example@example.com"},
},
{
// No user input. Content description and hint tex are non-empty.
{"email", "hint@example.com", "hint@example.com", true},
{"email hint@example.com", ""},
},
{
{"email", "editing_text", "hint@example.com", false},
{"email hint@example.com", "editing_text"},
},
{
{"", "", "", false},
{"", ""},
},
};
// Clearing string properties, the name and the value should not be populated. for (const auto& test_case : test_cases) {
root->string_properties->clear(); SetProperty(root, AXStringProperty::CONTENT_DESCRIPTION,
CallSerializeNode(root, &data); test_case.first.content_description);
ASSERT_FALSE( SetProperty(root, AXStringProperty::TEXT, test_case.first.text);
data->GetStringAttribute(ax::mojom::StringAttribute::kName, &prop)); SetProperty(root, AXStringProperty::HINT_TEXT, test_case.first.hint_text);
ASSERT_FALSE( SetProperty(root, AXBooleanProperty::SHOWING_HINT_TEXT,
data->GetStringAttribute(ax::mojom::StringAttribute::kValue, &prop)); test_case.first.showingHint);
CallSerializeNode(root, &data);
std::string prop;
ASSERT_EQ(
!test_case.second.name.empty(),
data->GetStringAttribute(ax::mojom::StringAttribute::kName, &prop));
if (!test_case.second.name.empty())
EXPECT_EQ(test_case.second.name, prop);
ASSERT_EQ(
!test_case.second.value.empty(),
data->GetStringAttribute(ax::mojom::StringAttribute::kValue, &prop));
if (!test_case.second.value.empty())
EXPECT_EQ(test_case.second.value, prop);
}
} }
TEST_F(AXTreeSourceArcTest, AccessibleNameComputationWindow) { TEST_F(AXTreeSourceArcTest, AccessibleNameComputationWindow) {
......
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