Commit 80b5e13b authored by Hiroki Sato's avatar Hiroki Sato Committed by Commit Bot

Handle VIEW_SELECTED event from list item in ArcA11yHelperBridge

Previously, Android's AccessibilityEvent.TYPE_VIEW_SELECTED is handled
as an event of changing value in ProgressBar or Slider in ARC++.
However, this event is usually used when selecting an item in
AdapterView (like ListView or GridView).

This CL modifies to handle both patterns of the event.

      app that ListView items can be selected and read by ChromeVox

Bug: b:130187244
Test: unit_tests --gtest_filter="ArcAccessibilityHelperBridgeTest.*"
Test: unit_tests --gtest_filter="AXTreeSourceArcTest.*"
Test: manually test with ag/9191465 using PlayStore and TalkBack test
Change-Id: If3af1bdc28490d00399fa89bd18258ff89731d19
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1746326
Commit-Queue: Hiroki Sato <hirokisato@chromium.org>
Reviewed-by: default avatarAlice Boxhall <aboxhall@chromium.org>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Reviewed-by: default avatarSara Kato <sarakato@chromium.org>
Cr-Commit-Position: refs/heads/master@{#695041}
parent 33457ed0
...@@ -366,8 +366,8 @@ void AccessibilityNodeInfoDataWrapper::Serialize( ...@@ -366,8 +366,8 @@ void AccessibilityNodeInfoDataWrapper::Serialize(
} }
// Range info. // Range info.
AXRangeInfoData* range_info = node_ptr_->range_info.get(); if (node_ptr_->range_info) {
if (range_info) { AXRangeInfoData* range_info = node_ptr_->range_info.get();
out_data->AddFloatAttribute(ax::mojom::FloatAttribute::kValueForRange, out_data->AddFloatAttribute(ax::mojom::FloatAttribute::kValueForRange,
range_info->current); range_info->current);
out_data->AddFloatAttribute(ax::mojom::FloatAttribute::kMinValueForRange, out_data->AddFloatAttribute(ax::mojom::FloatAttribute::kMinValueForRange,
......
...@@ -9,7 +9,9 @@ ...@@ -9,7 +9,9 @@
namespace arc { namespace arc {
ax::mojom::Event ToAXEvent(mojom::AccessibilityEventType arc_event_type) { ax::mojom::Event ToAXEvent(
mojom::AccessibilityEventType arc_event_type,
mojom::AccessibilityNodeInfoData* focused_node_info_data) {
switch (arc_event_type) { switch (arc_event_type) {
case mojom::AccessibilityEventType::VIEW_FOCUSED: case mojom::AccessibilityEventType::VIEW_FOCUSED:
case mojom::AccessibilityEventType::VIEW_ACCESSIBILITY_FOCUSED: case mojom::AccessibilityEventType::VIEW_ACCESSIBILITY_FOCUSED:
...@@ -32,8 +34,18 @@ ax::mojom::Event ToAXEvent(mojom::AccessibilityEventType arc_event_type) { ...@@ -32,8 +34,18 @@ ax::mojom::Event ToAXEvent(mojom::AccessibilityEventType arc_event_type) {
return ax::mojom::Event::kAlert; return ax::mojom::Event::kAlert;
case mojom::AccessibilityEventType::VIEW_SCROLLED: case mojom::AccessibilityEventType::VIEW_SCROLLED:
return ax::mojom::Event::kScrollPositionChanged; return ax::mojom::Event::kScrollPositionChanged;
case mojom::AccessibilityEventType::VIEW_SELECTED: case mojom::AccessibilityEventType::VIEW_SELECTED: {
return ax::mojom::Event::kValueChanged; // In Android, VIEW_SELECTED event is fired in the two cases below:
// 1. Changing a value in ProgressBar or TimePicker.
// (this usage is NOT documented)
// 2. Selecting an item in the context of an AdapterView.
// (officially documented in Android Developer doc below)
// https://developer.android.com/reference/android/view/accessibility/AccessibilityEvent#TYPE_VIEW_SELECTED
if (focused_node_info_data && focused_node_info_data->range_info)
return ax::mojom::Event::kValueChanged;
else
return ax::mojom::Event::kSelection;
}
case mojom::AccessibilityEventType::VIEW_HOVER_EXIT: case mojom::AccessibilityEventType::VIEW_HOVER_EXIT:
case mojom::AccessibilityEventType::TOUCH_EXPLORATION_GESTURE_START: case mojom::AccessibilityEventType::TOUCH_EXPLORATION_GESTURE_START:
case mojom::AccessibilityEventType::TOUCH_EXPLORATION_GESTURE_END: case mojom::AccessibilityEventType::TOUCH_EXPLORATION_GESTURE_END:
......
...@@ -12,9 +12,11 @@ ...@@ -12,9 +12,11 @@
namespace arc { namespace arc {
namespace mojom { namespace mojom {
enum class AccessibilityEventType; enum class AccessibilityEventType;
class AccessibilityNodeInfoData;
} // namespace mojom } // namespace mojom
ax::mojom::Event ToAXEvent(mojom::AccessibilityEventType arc_event_type); ax::mojom::Event ToAXEvent(mojom::AccessibilityEventType arc_event_type,
mojom::AccessibilityNodeInfoData* node_info_data);
} // namespace arc } // namespace arc
......
...@@ -189,7 +189,12 @@ void AXTreeSourceArc::NotifyAccessibilityEvent(AXEventData* event_data) { ...@@ -189,7 +189,12 @@ 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();
event.event_type = ToAXEvent(event_data->event_type); // When the focused node exists, give it as a hint to decide a Chrome
// automation event type.
AXNodeInfoData* opt_focused_node = nullptr;
if (tree_map_.find(focused_id_) != tree_map_.end())
opt_focused_node = tree_map_[focused_id_]->GetNode();
event.event_type = ToAXEvent(event_data->event_type, opt_focused_node);
event.id = event_data->source_id; event.id = event_data->source_id;
event_bundle.updates.emplace_back(); event_bundle.updates.emplace_back();
...@@ -200,22 +205,18 @@ void AXTreeSourceArc::NotifyAccessibilityEvent(AXEventData* event_data) { ...@@ -200,22 +205,18 @@ void AXTreeSourceArc::NotifyAccessibilityEvent(AXEventData* event_data) {
current_tree_serializer_->SerializeChanges(GetFromId(event_data->source_id), current_tree_serializer_->SerializeChanges(GetFromId(event_data->source_id),
&event_bundle.updates.back()); &event_bundle.updates.back());
extensions::AutomationEventRouter* router = GetAutomationEventRouter()->DispatchAccessibilityEvents(event_bundle);
extensions::AutomationEventRouter::GetInstance();
router->DispatchAccessibilityEvents(event_bundle);
} }
void AXTreeSourceArc::NotifyActionResult(const ui::AXActionData& data, void AXTreeSourceArc::NotifyActionResult(const ui::AXActionData& data,
bool result) { bool result) {
extensions::AutomationEventRouter::GetInstance()->DispatchActionResult( GetAutomationEventRouter()->DispatchActionResult(data, result);
data, result);
} }
void AXTreeSourceArc::NotifyGetTextLocationDataResult( void AXTreeSourceArc::NotifyGetTextLocationDataResult(
const ui::AXActionData& data, const ui::AXActionData& data,
const base::Optional<gfx::Rect>& rect) { const base::Optional<gfx::Rect>& rect) {
extensions::AutomationEventRouter::GetInstance() GetAutomationEventRouter()->DispatchGetTextLocationDataResult(data, rect);
->DispatchGetTextLocationDataResult(data, rect);
} }
bool AXTreeSourceArc::GetTreeData(ui::AXTreeData* data) const { bool AXTreeSourceArc::GetTreeData(ui::AXTreeData* data) const {
...@@ -443,12 +444,17 @@ void AXTreeSourceArc::Reset() { ...@@ -443,12 +444,17 @@ void AXTreeSourceArc::Reset() {
current_tree_serializer_.reset(new AXTreeArcSerializer(this)); current_tree_serializer_.reset(new AXTreeArcSerializer(this));
root_id_ = -1; root_id_ = -1;
focused_id_ = -1; focused_id_ = -1;
extensions::AutomationEventRouter* router = extensions::AutomationEventRouterInterface* router =
extensions::AutomationEventRouter::GetInstance(); GetAutomationEventRouter();
if (!router) if (!router)
return; return;
router->DispatchTreeDestroyedEvent(ax_tree_id(), nullptr); router->DispatchTreeDestroyedEvent(ax_tree_id(), nullptr);
} }
extensions::AutomationEventRouterInterface*
AXTreeSourceArc::GetAutomationEventRouter() const {
return extensions::AutomationEventRouter::GetInstance();
}
} // namespace arc } // namespace arc
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_info_data.h" #include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_info_data.h"
#include "components/arc/mojom/accessibility_helper.mojom.h" #include "components/arc/mojom/accessibility_helper.mojom.h"
#include "extensions/browser/api/automation_internal/automation_event_router.h"
#include "ui/accessibility/ax_action_handler.h" #include "ui/accessibility/ax_action_handler.h"
#include "ui/accessibility/ax_node.h" #include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_node_data.h" #include "ui/accessibility/ax_node_data.h"
...@@ -88,6 +89,10 @@ class AXTreeSourceArc : public ui::AXTreeSource<ArcAccessibilityInfoData*, ...@@ -88,6 +89,10 @@ class AXTreeSourceArc : public ui::AXTreeSource<ArcAccessibilityInfoData*,
bool is_input_method_window() { return is_input_method_window_; } bool is_input_method_window() { return is_input_method_window_; }
protected:
virtual extensions::AutomationEventRouterInterface* GetAutomationEventRouter()
const;
private: private:
friend class arc::AXTreeSourceArcTest; friend class arc::AXTreeSourceArcTest;
class FocusStealer; class FocusStealer;
......
...@@ -73,8 +73,9 @@ class AutomationEventRouter : public ui::AXEventBundleSink, ...@@ -73,8 +73,9 @@ class AutomationEventRouter : public ui::AXEventBundleSink,
content::BrowserContext* browser_context = nullptr) override; content::BrowserContext* browser_context = nullptr) override;
// Notify the source extension of the result to getTextLocation. // Notify the source extension of the result to getTextLocation.
void DispatchGetTextLocationDataResult(const ui::AXActionData& data, void DispatchGetTextLocationDataResult(
const base::Optional<gfx::Rect>& rect); const ui::AXActionData& data,
const base::Optional<gfx::Rect>& rect) override;
private: private:
struct AutomationListener { struct AutomationListener {
......
...@@ -51,6 +51,11 @@ class AutomationEventRouterInterface { ...@@ -51,6 +51,11 @@ class AutomationEventRouterInterface {
bool result, bool result,
content::BrowserContext* browser_context = nullptr) = 0; content::BrowserContext* browser_context = nullptr) = 0;
// Notify the source extension of the result to getTextLocation.
virtual void DispatchGetTextLocationDataResult(
const ui::AXActionData& data,
const base::Optional<gfx::Rect>& rect) {}
AutomationEventRouterInterface() {} AutomationEventRouterInterface() {}
virtual ~AutomationEventRouterInterface() {} virtual ~AutomationEventRouterInterface() {}
......
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