Chromium Code Reviews| Index: chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc |
| diff --git a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc b/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..7d2badf55bee0fd619dcb87f4f7bdcab7e1b5d28 |
| --- /dev/null |
| +++ b/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc |
| @@ -0,0 +1,214 @@ |
| +// Copyright 2017 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.h" |
| + |
| +#include "chrome/browser/extensions/api/automation_internal/automation_event_router.h" |
| +#include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h" |
| +#include "chrome/common/extensions/chrome_extension_messages.h" |
| +#include "components/exo/wm_helper.h" |
| +#include "ui/accessibility/ax_tree_id_registry.h" |
| +#include "ui/aura/window.h" |
| + |
| +namespace { |
| + |
| +ui::AXEvent ToAXEvent(arc::mojom::AccessibilityEventType arc_event_type) { |
| + switch (arc_event_type) { |
| + case arc::mojom::AccessibilityEventType::VIEW_FOCUSED: |
| + case arc::mojom::AccessibilityEventType::VIEW_ACCESSIBILITY_FOCUSED: |
| + return ui::AX_EVENT_FOCUS; |
| + case arc::mojom::AccessibilityEventType::VIEW_ACCESSIBILITY_FOCUS_CLEARED: |
| + return ui::AX_EVENT_BLUR; |
| + case arc::mojom::AccessibilityEventType::VIEW_CLICKED: |
| + case arc::mojom::AccessibilityEventType::VIEW_LONG_CLICKED: |
| + return ui::AX_EVENT_CLICKED; |
| + case arc::mojom::AccessibilityEventType::VIEW_TEXT_CHANGED: |
| + return ui::AX_EVENT_TEXT_CHANGED; |
| + case arc::mojom::AccessibilityEventType::VIEW_TEXT_SELECTION_CHANGED: |
| + return ui::AX_EVENT_TEXT_SELECTION_CHANGED; |
| + case arc::mojom::AccessibilityEventType::WINDOW_STATE_CHANGED: |
| + case arc::mojom::AccessibilityEventType::NOTIFICATION_STATE_CHANGED: |
| + case arc::mojom::AccessibilityEventType::WINDOW_CONTENT_CHANGED: |
| + case arc::mojom::AccessibilityEventType::WINDOWS_CHANGED: |
| + return ui::AX_EVENT_LAYOUT_COMPLETE; |
| + case arc::mojom::AccessibilityEventType::VIEW_HOVER_ENTER: |
| + return ui::AX_EVENT_FOCUS; |
| + case arc::mojom::AccessibilityEventType::ANNOUNCEMENT: |
| + return ui::AX_EVENT_ALERT; |
| + case arc::mojom::AccessibilityEventType::VIEW_SELECTED: |
| + case arc::mojom::AccessibilityEventType::VIEW_HOVER_EXIT: |
| + case arc::mojom::AccessibilityEventType::TOUCH_EXPLORATION_GESTURE_START: |
| + case arc::mojom::AccessibilityEventType::TOUCH_EXPLORATION_GESTURE_END: |
| + case arc::mojom::AccessibilityEventType::VIEW_SCROLLED: |
| + case arc::mojom::AccessibilityEventType:: |
| + VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY: |
| + case arc::mojom::AccessibilityEventType::GESTURE_DETECTION_START: |
| + case arc::mojom::AccessibilityEventType::GESTURE_DETECTION_END: |
| + case arc::mojom::AccessibilityEventType::TOUCH_INTERACTION_START: |
| + case arc::mojom::AccessibilityEventType::TOUCH_INTERACTION_END: |
| + case arc::mojom::AccessibilityEventType::VIEW_CONTEXT_CLICKED: |
| + case arc::mojom::AccessibilityEventType::ASSIST_READING_CONTEXT: |
| + return ui::AX_EVENT_CHILDREN_CHANGED; |
| + default: |
| + return ui::AX_EVENT_CHILDREN_CHANGED; |
| + } |
| + return ui::AX_EVENT_CHILDREN_CHANGED; |
| +} |
| + |
| +} // namespace |
| + |
| +namespace arc { |
| + |
| +AXTreeSourceArc::AXTreeSourceArc() |
| + : id_(ui::AXTreeIDRegistry::GetInstance()->CreateID()), |
| + current_tree_serializer_(new AXTreeArcSerializer(this)), |
| + root_id_(-1), |
| + focused_node_id_(-1) { |
| + set_owned_by_client(); |
| + SetFocusBehavior(views::View::FocusBehavior::ALWAYS); |
| +} |
| + |
| +AXTreeSourceArc::~AXTreeSourceArc() { |
| + Reset(); |
| +} |
| + |
| +void AXTreeSourceArc::NotifyAccessibilityEvent( |
| + mojom::AccessibilityEventData* event_data) { |
| + tree_map_.clear(); |
| + parent_map_.clear(); |
| + for (size_t i = 0; i < event_data->nodeData.size(); ++i) { |
| + for (size_t j = 0; j < event_data->nodeData[i]->childIds.size(); ++j) |
| + parent_map_[event_data->nodeData[i]->childIds[j]] = |
| + event_data->nodeData[i]->id; |
| + } |
| + |
| + for (size_t i = 0; i < event_data->nodeData.size(); ++i) { |
| + int32_t id = event_data->nodeData[i]->id; |
| + tree_map_[id] = event_data->nodeData[i].get(); |
| + if (parent_map_.find(id) == parent_map_.end()) |
| + root_id_ = id; |
|
dmazzoni
2017/02/09 01:18:09
Any other clue that we have the root?
Maybe asser
yawano
2017/02/09 10:55:29
Can we simply force that the first element in the
|
| + } |
| + |
| + ExtensionMsg_AccessibilityEventParams params; |
| + current_tree_serializer_->SerializeChanges(GetFromId(event_data->sourceId), |
| + ¶ms.update); |
| + params.tree_id = id_; |
| + params.id = event_data->sourceId; |
| + params.event_type = ToAXEvent(event_data->eventType); |
| + if (params.event_type == ui::AX_EVENT_FOCUS) |
| + focused_node_id_ = params.id; |
| + |
| + extensions::AutomationEventRouter* router = |
| + extensions::AutomationEventRouter::GetInstance(); |
| + router->DispatchAccessibilityEvent(params); |
| +} |
| + |
| +bool AXTreeSourceArc::GetTreeData(ui::AXTreeData* data) const { |
| + data->tree_id = id_; |
| + if (focused_node_id_ >= 0) |
| + data->focus_id = focused_node_id_; |
| + return true; |
| +} |
| + |
| +mojom::AccessibilityNodeInfoData* AXTreeSourceArc::GetRoot() const { |
| + mojom::AccessibilityNodeInfoData* root = GetFromId(root_id_); |
| + return root; |
| +} |
| + |
| +mojom::AccessibilityNodeInfoData* AXTreeSourceArc::GetFromId(int32_t id) const { |
| + auto it = tree_map_.find(id); |
| + if (it == tree_map_.end()) |
| + return nullptr; |
| + return it->second; |
| +} |
| + |
| +int32_t AXTreeSourceArc::GetId(mojom::AccessibilityNodeInfoData* node) const { |
| + if (!node) |
| + return -1; |
| + return node->id; |
| +} |
| + |
| +void AXTreeSourceArc::GetChildren( |
| + mojom::AccessibilityNodeInfoData* node, |
| + std::vector<mojom::AccessibilityNodeInfoData*>* out_children) const { |
| + if (!node) |
| + return; |
| + for (size_t i = 0; i < node->childIds.size(); ++i) { |
| + out_children->push_back(GetFromId(node->childIds[i])); |
| + } |
| +} |
| + |
| +mojom::AccessibilityNodeInfoData* AXTreeSourceArc::GetParent( |
| + mojom::AccessibilityNodeInfoData* node) const { |
| + if (!node) |
| + return nullptr; |
| + auto it = parent_map_.find(node->id); |
| + if (it != parent_map_.end()) |
| + return GetFromId(it->second); |
| + return nullptr; |
| +} |
| + |
| +bool AXTreeSourceArc::IsValid(mojom::AccessibilityNodeInfoData* node) const { |
| + return node; |
| +} |
| + |
| +bool AXTreeSourceArc::IsEqual(mojom::AccessibilityNodeInfoData* node1, |
| + mojom::AccessibilityNodeInfoData* node2) const { |
| + if (!node1 || !node2) |
| + return false; |
| + return node1->id == node2->id; |
| +} |
| + |
| +mojom::AccessibilityNodeInfoData* AXTreeSourceArc::GetNull() const { |
| + return nullptr; |
| +} |
| + |
| +void AXTreeSourceArc::SerializeNode(mojom::AccessibilityNodeInfoData* node, |
| + ui::AXNodeData* out_data) const { |
| + if (!node) |
| + return; |
| + out_data->id = node->id; |
| + out_data->state = 0; |
| + if (!node->text.empty()) |
| + out_data->SetName(node->text); |
| + else if (!node->contentDescription.empty()) |
| + out_data->SetName(node->contentDescription); |
| + |
| + int32_t id = node->id; |
| + if (id == root_id_) |
| + out_data->role = ui::AX_ROLE_ROOT_WEB_AREA; |
| + else if (!node->text.empty()) |
| + out_data->role = ui::AX_ROLE_STATIC_TEXT; |
| + else |
| + out_data->role = ui::AX_ROLE_DIV; |
| + |
| + exo::WMHelper* wmHelper = exo::WMHelper::GetInstance(); |
| + aura::Window* focused_window = wmHelper->GetFocusedWindow(); |
|
dmazzoni
2017/02/09 01:18:09
Maybe try to refactor this out and not call it on
|
| + gfx::Rect bounds_in_screen = node->boundsInScreen; |
| + if (focused_window) { |
| + aura::Window* toplevel_window = focused_window->GetToplevelWindow(); |
| + bounds_in_screen = gfx::ScaleToEnclosingRect( |
| + bounds_in_screen, |
| + 1.0f / toplevel_window->layer()->device_scale_factor()); |
| + } |
| + out_data->location.SetRect(bounds_in_screen.x(), bounds_in_screen.y(), |
| + bounds_in_screen.width(), |
| + bounds_in_screen.height()); |
| +} |
| + |
| +void AXTreeSourceArc::GetAccessibleNodeData(ui::AXNodeData* node_data) { |
| + node_data->AddIntAttribute(ui::AX_ATTR_CHILD_TREE_ID, id_); |
| + node_data->SetName("ExoShell"); |
| +} |
| + |
| +void AXTreeSourceArc::Reset() { |
| + tree_map_.clear(); |
| + parent_map_.clear(); |
| + current_tree_serializer_.reset(new AXTreeArcSerializer(this)); |
| + extensions::AutomationEventRouter* router = |
| + extensions::AutomationEventRouter::GetInstance(); |
| + router->DispatchTreeDestroyedEvent(id_, nullptr); |
| +} |
| + |
| +} // namespace arc |