Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(663)

Side by Side Diff: chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc

Issue 2726433002: Complete initial role and state mappings for ARC++ accessibility (Closed)
Patch Set: Export. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | content/browser/accessibility/browser_accessibility_android.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.h" 5 #include "chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "chrome/browser/extensions/api/automation_internal/automation_event_rou ter.h" 9 #include "chrome/browser/extensions/api/automation_internal/automation_event_rou ter.h"
10 #include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h" 10 #include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h"
11 #include "chrome/common/extensions/chrome_extension_messages.h" 11 #include "chrome/common/extensions/chrome_extension_messages.h"
12 #include "components/exo/wm_helper.h" 12 #include "components/exo/wm_helper.h"
13 #include "ui/accessibility/platform/ax_android_constants.h"
13 #include "ui/aura/window.h" 14 #include "ui/aura/window.h"
14 15
15 namespace { 16 namespace {
16 17
17 ui::AXEvent ToAXEvent(arc::mojom::AccessibilityEventType arc_event_type) { 18 ui::AXEvent ToAXEvent(arc::mojom::AccessibilityEventType arc_event_type) {
18 switch (arc_event_type) { 19 switch (arc_event_type) {
19 case arc::mojom::AccessibilityEventType::VIEW_FOCUSED: 20 case arc::mojom::AccessibilityEventType::VIEW_FOCUSED:
20 case arc::mojom::AccessibilityEventType::VIEW_ACCESSIBILITY_FOCUSED: 21 case arc::mojom::AccessibilityEventType::VIEW_ACCESSIBILITY_FOCUSED:
21 return ui::AX_EVENT_FOCUS; 22 return ui::AX_EVENT_FOCUS;
22 case arc::mojom::AccessibilityEventType::VIEW_ACCESSIBILITY_FOCUS_CLEARED: 23 case arc::mojom::AccessibilityEventType::VIEW_ACCESSIBILITY_FOCUS_CLEARED:
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
63 gfx::Rect bounds_in_screen = node->boundsInScreen; 64 gfx::Rect bounds_in_screen = node->boundsInScreen;
64 if (focused_window) { 65 if (focused_window) {
65 aura::Window* toplevel_window = focused_window->GetToplevelWindow(); 66 aura::Window* toplevel_window = focused_window->GetToplevelWindow();
66 return gfx::ScaleToEnclosingRect( 67 return gfx::ScaleToEnclosingRect(
67 bounds_in_screen, 68 bounds_in_screen,
68 1.0f / toplevel_window->layer()->device_scale_factor()); 69 1.0f / toplevel_window->layer()->device_scale_factor());
69 } 70 }
70 return bounds_in_screen; 71 return bounds_in_screen;
71 } 72 }
72 73
74 bool GetBooleanProperty(arc::mojom::AccessibilityNodeInfoData* node,
75 arc::mojom::AccessibilityBooleanProperty prop) {
76 if (!node->booleanProperties)
77 return false;
78
79 auto it = node->booleanProperties->find(prop);
80 if (it == node->booleanProperties->end())
81 return false;
82
83 return it->second;
84 }
85
73 bool GetStringProperty(arc::mojom::AccessibilityNodeInfoData* node, 86 bool GetStringProperty(arc::mojom::AccessibilityNodeInfoData* node,
74 arc::mojom::AccessibilityStringProperty prop, 87 arc::mojom::AccessibilityStringProperty prop,
75 std::string* out_value) { 88 std::string* out_value) {
76 if (!node->stringProperties) 89 if (!node->stringProperties)
77 return false; 90 return false;
78 91
79 auto it = node->stringProperties->find(prop); 92 auto it = node->stringProperties->find(prop);
80 if (it == node->stringProperties->end()) 93 if (it == node->stringProperties->end())
81 return false; 94 return false;
82 95
83 *out_value = it->second; 96 *out_value = it->second;
84 return true; 97 return true;
85 } 98 }
86 99
100 void PopulateAXRole(arc::mojom::AccessibilityNodeInfoData* node,
101 ui::AXNodeData* out_data) {
102 std::string class_name;
103 GetStringProperty(node, arc::mojom::AccessibilityStringProperty::CLASS_NAME,
104 &class_name);
105
106 #define MAP_ROLE(android_class_name, chrome_role) \
107 if (class_name == android_class_name) { \
108 out_data->role = chrome_role; \
109 return; \
110 }
111
112 // These mappings were taken from accessibility utils (Android -> Chrome) and
113 // BrowserAccessibilityAndroid. They do not completely match the above two
114 // sources.
115 MAP_ROLE(ui::kAXAbsListViewClassname, ui::AX_ROLE_LIST);
116 MAP_ROLE(ui::kAXButtonClassname, ui::AX_ROLE_BUTTON);
117 MAP_ROLE(ui::kAXCheckBoxClassname, ui::AX_ROLE_CHECK_BOX);
118 MAP_ROLE(ui::kAXCheckedTextViewClassname, ui::AX_ROLE_STATIC_TEXT);
119 MAP_ROLE(ui::kAXCompoundButtonClassname, ui::AX_ROLE_CHECK_BOX);
120 MAP_ROLE(ui::kAXDialogClassname, ui::AX_ROLE_DIALOG);
121 MAP_ROLE(ui::kAXEditTextClassname, ui::AX_ROLE_TEXT_FIELD);
122 MAP_ROLE(ui::kAXGridViewClassname, ui::AX_ROLE_TABLE);
123 MAP_ROLE(ui::kAXImageClassname, ui::AX_ROLE_IMAGE);
124 if (GetBooleanProperty(node,
125 arc::mojom::AccessibilityBooleanProperty::CLICKABLE)) {
126 MAP_ROLE(ui::kAXImageViewClassname, ui::AX_ROLE_BUTTON);
127 } else {
128 MAP_ROLE(ui::kAXImageViewClassname, ui::AX_ROLE_IMAGE);
129 }
130 MAP_ROLE(ui::kAXListViewClassname, ui::AX_ROLE_LIST);
131 MAP_ROLE(ui::kAXMenuItemClassname, ui::AX_ROLE_MENU_ITEM);
132 MAP_ROLE(ui::kAXPagerClassname, ui::AX_ROLE_SCROLL_AREA);
133 MAP_ROLE(ui::kAXProgressBarClassname, ui::AX_ROLE_PROGRESS_INDICATOR);
134 MAP_ROLE(ui::kAXRadioButtonClassname, ui::AX_ROLE_RADIO_BUTTON);
135 MAP_ROLE(ui::kAXSeekBarClassname, ui::AX_ROLE_SLIDER);
136 MAP_ROLE(ui::kAXSpinnerClassname, ui::AX_ROLE_POP_UP_BUTTON);
137 MAP_ROLE(ui::kAXSwitchClassname, ui::AX_ROLE_SWITCH);
138 MAP_ROLE(ui::kAXTabWidgetClassname, ui::AX_ROLE_TAB_LIST);
139 MAP_ROLE(ui::kAXToggleButtonClassname, ui::AX_ROLE_TOGGLE_BUTTON);
140 MAP_ROLE(ui::kAXViewClassname, ui::AX_ROLE_DIV);
141 MAP_ROLE(ui::kAXViewGroupClassname, ui::AX_ROLE_GROUP);
142 MAP_ROLE(ui::kAXWebViewClassname, ui::AX_ROLE_WEB_VIEW);
143
144 #undef MAP_ROLE
145
146 std::string text;
147 GetStringProperty(node, arc::mojom::AccessibilityStringProperty::TEXT, &text);
148 if (!text.empty())
149 out_data->role = ui::AX_ROLE_STATIC_TEXT;
150 else
151 out_data->role = ui::AX_ROLE_DIV;
152 }
153
154 void PopulateAXState(arc::mojom::AccessibilityNodeInfoData* node,
155 ui::AXNodeData* out_data) {
156 out_data->state = 0;
157
158 #define MAP_STATE(android_boolean_property, chrome_state) \
159 if (GetBooleanProperty(node, android_boolean_property)) \
160 out_data->AddStateFlag(chrome_state);
161
162 using AXBooleanProperty = arc::mojom::AccessibilityBooleanProperty;
163
164 // These mappings were taken from accessibility utils (Android -> Chrome) and
165 // BrowserAccessibilityAndroid. They do not completely match the above two
166 // sources.
167 // The FOCUSABLE state is not mapped because Android places focusability on
168 // many ancestor nodes.
169 MAP_STATE(AXBooleanProperty::CHECKED, ui::AX_STATE_CHECKED);
170 MAP_STATE(AXBooleanProperty::EDITABLE, ui::AX_STATE_EDITABLE);
171 MAP_STATE(AXBooleanProperty::MULTI_LINE, ui::AX_STATE_MULTILINE);
172 MAP_STATE(AXBooleanProperty::PASSWORD, ui::AX_STATE_PROTECTED);
173 MAP_STATE(AXBooleanProperty::SELECTED, ui::AX_STATE_SELECTED);
174
175 #undef MAP_STATE
176
177 if (!GetBooleanProperty(node, AXBooleanProperty::ENABLED))
178 out_data->AddStateFlag(ui::AX_STATE_DISABLED);
179 }
180
87 } // namespace 181 } // namespace
88 182
89 namespace arc { 183 namespace arc {
90 184
91 AXTreeSourceArc::AXTreeSourceArc(int32_t id) 185 AXTreeSourceArc::AXTreeSourceArc(int32_t id)
92 : tree_id_(id), 186 : tree_id_(id),
93 current_tree_serializer_(new AXTreeArcSerializer(this)), 187 current_tree_serializer_(new AXTreeArcSerializer(this)),
94 root_id_(-1), 188 root_id_(-1),
95 focused_node_id_(-1) {} 189 focused_node_id_(-1) {}
96 190
97 AXTreeSourceArc::~AXTreeSourceArc() { 191 AXTreeSourceArc::~AXTreeSourceArc() {
98 Reset(); 192 Reset();
99 } 193 }
100 194
101 void AXTreeSourceArc::NotifyAccessibilityEvent( 195 void AXTreeSourceArc::NotifyAccessibilityEvent(
102 mojom::AccessibilityEventData* event_data) { 196 mojom::AccessibilityEventData* event_data) {
103 tree_map_.clear(); 197 tree_map_.clear();
104 parent_map_.clear(); 198 parent_map_.clear();
105 root_id_ = -1; 199 root_id_ = -1;
106 focused_node_id_ = -1;
107 for (size_t i = 0; i < event_data->nodeData.size(); ++i) { 200 for (size_t i = 0; i < event_data->nodeData.size(); ++i) {
108 if (!event_data->nodeData[i]->intListProperties) 201 if (!event_data->nodeData[i]->intListProperties)
109 continue; 202 continue;
110 auto it = event_data->nodeData[i]->intListProperties->find( 203 auto it = event_data->nodeData[i]->intListProperties->find(
111 arc::mojom::AccessibilityIntListProperty::CHILD_NODE_IDS); 204 arc::mojom::AccessibilityIntListProperty::CHILD_NODE_IDS);
112 if (it != event_data->nodeData[i]->intListProperties->end()) { 205 if (it != event_data->nodeData[i]->intListProperties->end()) {
113 for (size_t j = 0; j < it->second.size(); ++j) 206 for (size_t j = 0; j < it->second.size(); ++j)
114 parent_map_[it->second[j]] = event_data->nodeData[i]->id; 207 parent_map_[it->second[j]] = event_data->nodeData[i]->id;
115 } 208 }
116 } 209 }
117 210
118 for (size_t i = 0; i < event_data->nodeData.size(); ++i) { 211 for (size_t i = 0; i < event_data->nodeData.size(); ++i) {
119 int32_t id = event_data->nodeData[i]->id; 212 int32_t id = event_data->nodeData[i]->id;
120 tree_map_[id] = event_data->nodeData[i].get(); 213 tree_map_[id] = event_data->nodeData[i].get();
121 if (parent_map_.find(id) == parent_map_.end()) { 214 if (parent_map_.find(id) == parent_map_.end()) {
122 CHECK_EQ(-1, root_id_) << "Duplicated root"; 215 CHECK_EQ(-1, root_id_) << "Duplicated root";
123 root_id_ = id; 216 root_id_ = id;
124 } 217 }
125 } 218 }
126 219
127 ExtensionMsg_AccessibilityEventParams params; 220 ExtensionMsg_AccessibilityEventParams params;
128 params.event_type = ToAXEvent(event_data->eventType); 221 params.event_type = ToAXEvent(event_data->eventType);
129 if (params.event_type == ui::AX_EVENT_FOCUS) 222 if (params.event_type == ui::AX_EVENT_FOCUS)
130 focused_node_id_ = params.id; 223 focused_node_id_ = params.id;
224 else if (params.event_type == ui::AX_EVENT_BLUR)
225 focused_node_id_ = -1;
131 params.tree_id = tree_id_; 226 params.tree_id = tree_id_;
132 params.id = event_data->sourceId; 227 params.id = event_data->sourceId;
133 228
134 current_tree_serializer_->SerializeChanges(GetFromId(event_data->sourceId), 229 current_tree_serializer_->SerializeChanges(GetFromId(event_data->sourceId),
135 &params.update); 230 &params.update);
136 231
137 extensions::AutomationEventRouter* router = 232 extensions::AutomationEventRouter* router =
138 extensions::AutomationEventRouter::GetInstance(); 233 extensions::AutomationEventRouter::GetInstance();
139 router->DispatchAccessibilityEvent(params); 234 router->DispatchAccessibilityEvent(params);
140 } 235 }
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
203 298
204 mojom::AccessibilityNodeInfoData* AXTreeSourceArc::GetNull() const { 299 mojom::AccessibilityNodeInfoData* AXTreeSourceArc::GetNull() const {
205 return nullptr; 300 return nullptr;
206 } 301 }
207 302
208 void AXTreeSourceArc::SerializeNode(mojom::AccessibilityNodeInfoData* node, 303 void AXTreeSourceArc::SerializeNode(mojom::AccessibilityNodeInfoData* node,
209 ui::AXNodeData* out_data) const { 304 ui::AXNodeData* out_data) const {
210 if (!node) 305 if (!node)
211 return; 306 return;
212 out_data->id = node->id; 307 out_data->id = node->id;
213 out_data->state = 0;
214 308
215 using AXStringProperty = arc::mojom::AccessibilityStringProperty; 309 using AXStringProperty = arc::mojom::AccessibilityStringProperty;
216 std::string text; 310 std::string text;
217 if (GetStringProperty(node, AXStringProperty::TEXT, &text)) 311 if (GetStringProperty(node, AXStringProperty::TEXT, &text))
218 out_data->SetName(text); 312 out_data->SetName(text);
219 else if (GetStringProperty(node, AXStringProperty::CONTENT_DESCRIPTION, 313 else if (GetStringProperty(node, AXStringProperty::CONTENT_DESCRIPTION,
220 &text)) 314 &text))
221 out_data->SetName(text); 315 out_data->SetName(text);
222 316
223 int32_t id = node->id; 317 int32_t id = node->id;
224 if (id == root_id_) 318 if (id == root_id_)
225 out_data->role = ui::AX_ROLE_ROOT_WEB_AREA; 319 out_data->role = ui::AX_ROLE_ROOT_WEB_AREA;
226 else if (!text.empty())
227 out_data->role = ui::AX_ROLE_STATIC_TEXT;
228 else 320 else
229 out_data->role = ui::AX_ROLE_DIV; 321 PopulateAXRole(node, out_data);
322
323 PopulateAXState(node, out_data);
230 324
231 const gfx::Rect bounds_in_screen = GetBounds(node); 325 const gfx::Rect bounds_in_screen = GetBounds(node);
232 out_data->location.SetRect(bounds_in_screen.x(), bounds_in_screen.y(), 326 out_data->location.SetRect(bounds_in_screen.x(), bounds_in_screen.y(),
233 bounds_in_screen.width(), 327 bounds_in_screen.width(),
234 bounds_in_screen.height()); 328 bounds_in_screen.height());
329
330 if (out_data->role == ui::AX_ROLE_TEXT_FIELD && !text.empty())
331 out_data->AddStringAttribute(ui::AX_ATTR_VALUE, text);
235 } 332 }
236 333
237 void AXTreeSourceArc::Reset() { 334 void AXTreeSourceArc::Reset() {
238 tree_map_.clear(); 335 tree_map_.clear();
239 parent_map_.clear(); 336 parent_map_.clear();
240 current_tree_serializer_.reset(new AXTreeArcSerializer(this)); 337 current_tree_serializer_.reset(new AXTreeArcSerializer(this));
241 root_id_ = -1; 338 root_id_ = -1;
242 focused_node_id_ = -1; 339 focused_node_id_ = -1;
243 extensions::AutomationEventRouter* router = 340 extensions::AutomationEventRouter* router =
244 extensions::AutomationEventRouter::GetInstance(); 341 extensions::AutomationEventRouter::GetInstance();
245 router->DispatchTreeDestroyedEvent(tree_id_, nullptr); 342 router->DispatchTreeDestroyedEvent(tree_id_, nullptr);
246 } 343 }
247 344
248 } // namespace arc 345 } // namespace arc
OLDNEW
« no previous file with comments | « no previous file | content/browser/accessibility/browser_accessibility_android.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698