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

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: Clear focused node id only on blur. 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 ui::AXRole GetAXRole(arc::mojom::AccessibilityNodeInfoData* node) {
101 std::string class_name, text;
102 GetStringProperty(node, arc::mojom::AccessibilityStringProperty::CLASS_NAME,
103 &class_name);
104 GetStringProperty(node, arc::mojom::AccessibilityStringProperty::TEXT, &text);
yawano 2017/02/28 05:36:07 nit: We can get this later. We are not using the t
105
106 #define MAP_ROLE(android_class_name, chrome_role) \
dmazzoni 2017/02/28 04:31:25 Perhaps these should be a hash_map from string to
David Tseng 2017/02/28 18:52:30 It's not one to one and will probably be less so a
107 if (class_name == android_class_name) \
108 return chrome_role;
109
110 MAP_ROLE(ui::kAXAbsListViewClassname, ui::AX_ROLE_LIST);
111 MAP_ROLE(ui::kAXButtonClassname, ui::AX_ROLE_BUTTON);
112 MAP_ROLE(ui::kAXCheckBoxClassname, ui::AX_ROLE_CHECK_BOX);
113 MAP_ROLE(ui::kAXCompoundButtonClassname, ui::AX_ROLE_CHECK_BOX);
114 MAP_ROLE(ui::kAXCheckedTextViewClassname, ui::AX_ROLE_STATIC_TEXT);
115 MAP_ROLE(ui::kAXDialogClassname, ui::AX_ROLE_DIALOG);
116 MAP_ROLE(ui::kAXEditTextClassname, ui::AX_ROLE_TEXT_FIELD);
117 MAP_ROLE(ui::kAXGridViewClassname, ui::AX_ROLE_TABLE);
118 MAP_ROLE(ui::kAXImageClassname, ui::AX_ROLE_IMAGE);
119 if (GetBooleanProperty(node,
120 arc::mojom::AccessibilityBooleanProperty::CLICKABLE)) {
121 MAP_ROLE(ui::kAXImageViewClassname, ui::AX_ROLE_BUTTON);
122 } else {
123 MAP_ROLE(ui::kAXImageViewClassname, ui::AX_ROLE_IMAGE);
124 }
125 MAP_ROLE(ui::kAXListViewClassname, ui::AX_ROLE_LIST);
126 MAP_ROLE(ui::kAXMenuItemClassname, ui::AX_ROLE_MENU_ITEM);
127 MAP_ROLE(ui::kAXPagerClassname, ui::AX_ROLE_BUTTON);
128 MAP_ROLE(ui::kAXProgressBarClassname, ui::AX_ROLE_PROGRESS_INDICATOR);
129 MAP_ROLE(ui::kAXRadioButtonClassname, ui::AX_ROLE_RADIO_BUTTON);
130 MAP_ROLE(ui::kAXSeekBarClassname, ui::AX_ROLE_SLIDER);
131 MAP_ROLE(ui::kAXSwitchClassname, ui::AX_ROLE_SWITCH);
132 MAP_ROLE(ui::kAXSpinnerClassname, ui::AX_ROLE_SPIN_BUTTON);
yawano 2017/02/28 05:36:07 question: We have different mapping for AX_ROLE_SP
David Tseng 2017/02/28 18:50:37 I think the more appropriate mapping isto a pop_up
yawano 2017/03/01 03:49:51 sgtm.
133 MAP_ROLE(ui::kAXTabWidgetClassname, ui::AX_ROLE_TAB_LIST);
134 MAP_ROLE(ui::kAXToggleButtonClassname, ui::AX_ROLE_TOGGLE_BUTTON);
135 MAP_ROLE(ui::kAXViewClassname, ui::AX_ROLE_DIV);
136 MAP_ROLE(ui::kAXViewGroupClassname, ui::AX_ROLE_GROUP);
137 MAP_ROLE(ui::kAXWebViewClassname, ui::AX_ROLE_WEB_VIEW);
138
139 #undef MAP_ROLE
140
141 if (!text.empty())
dmazzoni 2017/02/28 04:31:25 How about only if it's a leaf node. The rest of th
David Tseng 2017/02/28 18:50:37 This is the fallback case (in case we can't assign
142 return ui::AX_ROLE_STATIC_TEXT;
143 else
144 return ui::AX_ROLE_DIV;
145 }
146
147 int32_t GetAXState(arc::mojom::AccessibilityNodeInfoData* node) {
148 int32_t state = 0;
149
150 #define MAP_STATE(android_boolean_property, chrome_state) \
151 if (GetBooleanProperty(node, android_boolean_property)) \
152 state |= 1 << chrome_state;
yawano 2017/02/28 05:36:07 Can we change GetAxState to be passed AxNodeData a
David Tseng 2017/02/28 18:50:37 Done
153
154 using AXBooleanProperty = arc::mojom::AccessibilityBooleanProperty;
155
156 MAP_STATE(AXBooleanProperty::CHECKED, ui::AX_STATE_CHECKED);
157 MAP_STATE(AXBooleanProperty::EDITABLE, ui::AX_STATE_EDITABLE);
158 MAP_STATE(AXBooleanProperty::FOCUSABLE, ui::AX_STATE_FOCUSABLE);
159 MAP_STATE(AXBooleanProperty::MULTI_LINE, ui::AX_STATE_MULTILINE);
160 MAP_STATE(AXBooleanProperty::PASSWORD, ui::AX_STATE_PROTECTED);
161 MAP_STATE(AXBooleanProperty::SELECTED, ui::AX_STATE_SELECTED);
162
163 #undef MAP_STATE
164
165 if (!GetBooleanProperty(node, AXBooleanProperty::ENABLED))
166 state |= 1 << ui::AX_STATE_DISABLED;
167
168 return state;
169 }
170
87 } // namespace 171 } // namespace
88 172
89 namespace arc { 173 namespace arc {
90 174
91 AXTreeSourceArc::AXTreeSourceArc(int32_t id) 175 AXTreeSourceArc::AXTreeSourceArc(int32_t id)
92 : tree_id_(id), 176 : tree_id_(id),
93 current_tree_serializer_(new AXTreeArcSerializer(this)), 177 current_tree_serializer_(new AXTreeArcSerializer(this)),
94 root_id_(-1), 178 root_id_(-1),
95 focused_node_id_(-1) {} 179 focused_node_id_(-1) {}
96 180
97 AXTreeSourceArc::~AXTreeSourceArc() { 181 AXTreeSourceArc::~AXTreeSourceArc() {
98 Reset(); 182 Reset();
99 } 183 }
100 184
101 void AXTreeSourceArc::NotifyAccessibilityEvent( 185 void AXTreeSourceArc::NotifyAccessibilityEvent(
102 mojom::AccessibilityEventData* event_data) { 186 mojom::AccessibilityEventData* event_data) {
103 tree_map_.clear(); 187 tree_map_.clear();
104 parent_map_.clear(); 188 parent_map_.clear();
105 root_id_ = -1; 189 root_id_ = -1;
106 focused_node_id_ = -1;
107 for (size_t i = 0; i < event_data->nodeData.size(); ++i) { 190 for (size_t i = 0; i < event_data->nodeData.size(); ++i) {
108 if (!event_data->nodeData[i]->intListProperties) 191 if (!event_data->nodeData[i]->intListProperties)
109 continue; 192 continue;
110 auto it = event_data->nodeData[i]->intListProperties->find( 193 auto it = event_data->nodeData[i]->intListProperties->find(
111 arc::mojom::AccessibilityIntListProperty::CHILD_NODE_IDS); 194 arc::mojom::AccessibilityIntListProperty::CHILD_NODE_IDS);
112 if (it != event_data->nodeData[i]->intListProperties->end()) { 195 if (it != event_data->nodeData[i]->intListProperties->end()) {
113 for (size_t j = 0; j < it->second.size(); ++j) 196 for (size_t j = 0; j < it->second.size(); ++j)
114 parent_map_[it->second[j]] = event_data->nodeData[i]->id; 197 parent_map_[it->second[j]] = event_data->nodeData[i]->id;
115 } 198 }
116 } 199 }
117 200
118 for (size_t i = 0; i < event_data->nodeData.size(); ++i) { 201 for (size_t i = 0; i < event_data->nodeData.size(); ++i) {
119 int32_t id = event_data->nodeData[i]->id; 202 int32_t id = event_data->nodeData[i]->id;
120 tree_map_[id] = event_data->nodeData[i].get(); 203 tree_map_[id] = event_data->nodeData[i].get();
121 if (parent_map_.find(id) == parent_map_.end()) { 204 if (parent_map_.find(id) == parent_map_.end()) {
122 CHECK_EQ(-1, root_id_) << "Duplicated root"; 205 CHECK_EQ(-1, root_id_) << "Duplicated root";
123 root_id_ = id; 206 root_id_ = id;
124 } 207 }
125 } 208 }
126 209
127 ExtensionMsg_AccessibilityEventParams params; 210 ExtensionMsg_AccessibilityEventParams params;
128 params.event_type = ToAXEvent(event_data->eventType); 211 params.event_type = ToAXEvent(event_data->eventType);
129 if (params.event_type == ui::AX_EVENT_FOCUS) 212 if (params.event_type == ui::AX_EVENT_FOCUS)
130 focused_node_id_ = params.id; 213 focused_node_id_ = params.id;
214 else if (params.event_type == ui::AX_EVENT_BLUR)
215 focused_node_id_ = -1;
131 params.tree_id = tree_id_; 216 params.tree_id = tree_id_;
132 params.id = event_data->sourceId; 217 params.id = event_data->sourceId;
133 218
134 current_tree_serializer_->SerializeChanges(GetFromId(event_data->sourceId), 219 current_tree_serializer_->SerializeChanges(GetFromId(event_data->sourceId),
135 &params.update); 220 &params.update);
136 221
137 extensions::AutomationEventRouter* router = 222 extensions::AutomationEventRouter* router =
138 extensions::AutomationEventRouter::GetInstance(); 223 extensions::AutomationEventRouter::GetInstance();
139 router->DispatchAccessibilityEvent(params); 224 router->DispatchAccessibilityEvent(params);
140 } 225 }
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
203 288
204 mojom::AccessibilityNodeInfoData* AXTreeSourceArc::GetNull() const { 289 mojom::AccessibilityNodeInfoData* AXTreeSourceArc::GetNull() const {
205 return nullptr; 290 return nullptr;
206 } 291 }
207 292
208 void AXTreeSourceArc::SerializeNode(mojom::AccessibilityNodeInfoData* node, 293 void AXTreeSourceArc::SerializeNode(mojom::AccessibilityNodeInfoData* node,
209 ui::AXNodeData* out_data) const { 294 ui::AXNodeData* out_data) const {
210 if (!node) 295 if (!node)
211 return; 296 return;
212 out_data->id = node->id; 297 out_data->id = node->id;
213 out_data->state = 0;
214 298
215 using AXStringProperty = arc::mojom::AccessibilityStringProperty; 299 using AXStringProperty = arc::mojom::AccessibilityStringProperty;
216 std::string text; 300 std::string text;
217 if (GetStringProperty(node, AXStringProperty::TEXT, &text)) 301 if (GetStringProperty(node, AXStringProperty::TEXT, &text))
218 out_data->SetName(text); 302 out_data->SetName(text);
219 else if (GetStringProperty(node, AXStringProperty::CONTENT_DESCRIPTION, 303 else if (GetStringProperty(node, AXStringProperty::CONTENT_DESCRIPTION,
220 &text)) 304 &text))
221 out_data->SetName(text); 305 out_data->SetName(text);
222 306
223 int32_t id = node->id; 307 int32_t id = node->id;
224 if (id == root_id_) 308 if (id == root_id_)
225 out_data->role = ui::AX_ROLE_ROOT_WEB_AREA; 309 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 310 else
229 out_data->role = ui::AX_ROLE_DIV; 311 out_data->role = GetAXRole(node);
312
313 out_data->state = GetAXState(node);
230 314
231 const gfx::Rect bounds_in_screen = GetBounds(node); 315 const gfx::Rect bounds_in_screen = GetBounds(node);
232 out_data->location.SetRect(bounds_in_screen.x(), bounds_in_screen.y(), 316 out_data->location.SetRect(bounds_in_screen.x(), bounds_in_screen.y(),
233 bounds_in_screen.width(), 317 bounds_in_screen.width(),
234 bounds_in_screen.height()); 318 bounds_in_screen.height());
319
320 if (out_data->role == ui::AX_ROLE_TEXT_FIELD && !text.empty())
321 out_data->AddStringAttribute(ui::AX_ATTR_VALUE, text);
235 } 322 }
236 323
237 void AXTreeSourceArc::Reset() { 324 void AXTreeSourceArc::Reset() {
238 tree_map_.clear(); 325 tree_map_.clear();
239 parent_map_.clear(); 326 parent_map_.clear();
240 current_tree_serializer_.reset(new AXTreeArcSerializer(this)); 327 current_tree_serializer_.reset(new AXTreeArcSerializer(this));
241 root_id_ = -1; 328 root_id_ = -1;
242 focused_node_id_ = -1; 329 focused_node_id_ = -1;
243 extensions::AutomationEventRouter* router = 330 extensions::AutomationEventRouter* router =
244 extensions::AutomationEventRouter::GetInstance(); 331 extensions::AutomationEventRouter::GetInstance();
245 router->DispatchTreeDestroyedEvent(tree_id_, nullptr); 332 router->DispatchTreeDestroyedEvent(tree_id_, nullptr);
246 } 333 }
247 334
248 } // namespace arc 335 } // 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