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

Ensure ARC accessibility focus is on important node

Sometimes Android sends a focus event to non-important node, which makes
ChromeVox focus gets lost.

This CL changes AXTreeSource to adjust focused node to be on an
important node.

Bug: b/148356932
Test: unit_tests --gtest_filter="AXTreeSourceArcTest.*"
Test: manual. Open PlayStore, press install button of an app with in-purchase when touch mode is off. Ensure focus isn't lost.
Change-Id: Ic19796d7b0d7abbeb1ff7a0e72ef3770346b1de1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2086462Reviewed-by: default avatarDavid Tseng <dtseng@chromium.org>
Reviewed-by: default avatarSara Kato <sarakato@chromium.org>
Commit-Queue: Hiroki Sato <hirokisato@chromium.org>
Cr-Commit-Position: refs/heads/master@{#747071}
parent a863086a
...@@ -179,6 +179,24 @@ void AXTreeSourceArc::NotifyAccessibilityEvent(AXEventData* event_data) { ...@@ -179,6 +179,24 @@ void AXTreeSourceArc::NotifyAccessibilityEvent(AXEventData* event_data) {
} }
} }
AXNodeInfoData* focused_node =
android_focused_id_.has_value()
? GetFromId(*android_focused_id_)->GetNode()
: nullptr;
// Ensure that the focused node correctly gets focus.
while (android_focused_id_.has_value() && android_focused_id_ != root_id_ &&
!IsImportantInAndroid(focused_node)) {
AccessibilityInfoDataWrapper* parent =
GetFromId(parent_map_[*android_focused_id_]);
if (parent && parent->IsNode()) {
android_focused_id_ = parent->GetId();
focused_node = parent->GetNode();
} else {
break;
}
}
ApplyCachedProperties(); ApplyCachedProperties();
ExtensionMsg_AccessibilityEventBundleParams event_bundle; ExtensionMsg_AccessibilityEventBundleParams event_bundle;
...@@ -186,13 +204,6 @@ void AXTreeSourceArc::NotifyAccessibilityEvent(AXEventData* event_data) { ...@@ -186,13 +204,6 @@ void AXTreeSourceArc::NotifyAccessibilityEvent(AXEventData* event_data) {
event_bundle.events.emplace_back(); event_bundle.events.emplace_back();
ui::AXEvent& event = event_bundle.events.back(); ui::AXEvent& event = event_bundle.events.back();
// When the focused node exists, give it as a hint to decide a Chrome
// automation event type.
AXNodeInfoData* focused_node = nullptr;
if (android_focused_id_.has_value() &&
tree_map_.find(*android_focused_id_) != tree_map_.end())
focused_node = tree_map_[*android_focused_id_]->GetNode();
event.event_type = ToAXEvent(event_data->event_type, focused_node); event.event_type = ToAXEvent(event_data->event_type, focused_node);
event.id = event_data->source_id; event.id = event_data->source_id;
......
...@@ -925,6 +925,7 @@ TEST_F(AXTreeSourceArcTest, OnViewSelectedEvent) { ...@@ -925,6 +925,7 @@ TEST_F(AXTreeSourceArcTest, OnViewSelectedEvent) {
AXNodeInfoData* button = event->node_data.back().get(); AXNodeInfoData* button = event->node_data.back().get();
button->id = 1; button->id = 1;
SetProperty(button, AXBooleanProperty::FOCUSABLE, true); SetProperty(button, AXBooleanProperty::FOCUSABLE, true);
SetProperty(button, AXBooleanProperty::IMPORTANCE, true);
// Ensure that button has a focus. // Ensure that button has a focus.
event->event_type = AXEventType::VIEW_FOCUSED; event->event_type = AXEventType::VIEW_FOCUSED;
...@@ -1255,13 +1256,27 @@ TEST_F(AXTreeSourceArcTest, SyncFocus) { ...@@ -1255,13 +1256,27 @@ TEST_F(AXTreeSourceArcTest, SyncFocus) {
SetProperty(node2, AXBooleanProperty::IMPORTANCE, true); SetProperty(node2, AXBooleanProperty::IMPORTANCE, true);
node2->bounds_in_screen = gfx::Rect(50, 50, 100, 100); node2->bounds_in_screen = gfx::Rect(50, 50, 100, 100);
CallNotifyAccessibilityEvent(event.get()); // Add a child node to |node1|, but it's not an important node.
SetProperty(node1, AXIntListProperty::CHILD_NODE_IDS, std::vector<int>({3}));
event->node_data.emplace_back(AXNodeInfoData::New());
AXNodeInfoData* node3 = event->node_data.back().get();
node3->id = 3;
// Initially |node1| has a focus. // Initially |node1| has a focus.
CallNotifyAccessibilityEvent(event.get());
ui::AXTreeData data; ui::AXTreeData data;
EXPECT_TRUE(CallGetTreeData(&data)); EXPECT_TRUE(CallGetTreeData(&data));
EXPECT_EQ(node1->id, data.focus_id); EXPECT_EQ(node1->id, data.focus_id);
// Focus event to a non-important node. The descendant important node |node1|
// gets focus instead.
event->source_id = node3->id;
event->event_type = AXEventType::VIEW_FOCUSED;
CallNotifyAccessibilityEvent(event.get());
EXPECT_TRUE(CallGetTreeData(&data));
EXPECT_EQ(node1->id, data.focus_id);
// Move Chrome accessibility focus to |node2|. // Move Chrome accessibility focus to |node2|.
CallUpdateAccessibilityFocusLocation(node2->id); CallUpdateAccessibilityFocusLocation(node2->id);
......
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