OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "content/browser/accessibility/browser_accessibility_android.h" | 5 #include "content/browser/accessibility/browser_accessibility_android.h" |
6 | 6 |
7 #include "base/strings/utf_string_conversions.h" | 7 #include "base/strings/utf_string_conversions.h" |
8 #include "content/browser/accessibility/browser_accessibility_manager_android.h" | 8 #include "content/browser/accessibility/browser_accessibility_manager_android.h" |
9 #include "content/common/accessibility_messages.h" | 9 #include "content/common/accessibility_messages.h" |
10 #include "content/common/accessibility_node_data.h" | 10 #include "content/common/accessibility_node_data.h" |
11 | 11 |
| 12 namespace { |
| 13 |
| 14 // These are enums from android.text.InputType in Java: |
| 15 enum { |
| 16 ANDROID_TEXT_INPUTTYPE_TYPE_NULL = 0, |
| 17 ANDROID_TEXT_INPUTTYPE_TYPE_DATETIME = 0x4, |
| 18 ANDROID_TEXT_INPUTTYPE_TYPE_DATETIME_DATE = 0x14, |
| 19 ANDROID_TEXT_INPUTTYPE_TYPE_DATETIME_TIME = 0x24, |
| 20 ANDROID_TEXT_INPUTTYPE_TYPE_NUMBER = 0x2, |
| 21 ANDROID_TEXT_INPUTTYPE_TYPE_PHONE = 0x3, |
| 22 ANDROID_TEXT_INPUTTYPE_TYPE_TEXT = 0x1, |
| 23 ANDROID_TEXT_INPUTTYPE_TYPE_TEXT_URI = 0x11, |
| 24 ANDROID_TEXT_INPUTTYPE_TYPE_TEXT_WEB_EDIT_TEXT = 0xa1, |
| 25 ANDROID_TEXT_INPUTTYPE_TYPE_TEXT_WEB_EMAIL = 0xd1, |
| 26 ANDROID_TEXT_INPUTTYPE_TYPE_TEXT_WEB_PASSWORD = 0xe1 |
| 27 }; |
| 28 |
| 29 // These are enums from android.view.View in Java: |
| 30 enum { |
| 31 ANDROID_VIEW_VIEW_ACCESSIBILITY_LIVE_REGION_NONE = 0, |
| 32 ANDROID_VIEW_VIEW_ACCESSIBILITY_LIVE_REGION_POLITE = 1, |
| 33 ANDROID_VIEW_VIEW_ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 2 |
| 34 }; |
| 35 |
| 36 // These are enums from |
| 37 // android.view.accessibility.AccessibilityNodeInfo.RangeInfo in Java: |
| 38 enum { |
| 39 ANDROID_VIEW_ACCESSIBILITY_RANGE_TYPE_FLOAT = 1 |
| 40 }; |
| 41 |
| 42 } // namespace |
| 43 |
12 namespace content { | 44 namespace content { |
13 | 45 |
14 // static | 46 // static |
15 BrowserAccessibility* BrowserAccessibility::Create() { | 47 BrowserAccessibility* BrowserAccessibility::Create() { |
16 return new BrowserAccessibilityAndroid(); | 48 return new BrowserAccessibilityAndroid(); |
17 } | 49 } |
18 | 50 |
19 BrowserAccessibilityAndroid::BrowserAccessibilityAndroid() { | 51 BrowserAccessibilityAndroid::BrowserAccessibilityAndroid() { |
20 first_time_ = true; | 52 first_time_ = true; |
21 } | 53 } |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
71 } | 103 } |
72 | 104 |
73 bool BrowserAccessibilityAndroid::IsChecked() const { | 105 bool BrowserAccessibilityAndroid::IsChecked() const { |
74 return HasState(blink::WebAXStateChecked); | 106 return HasState(blink::WebAXStateChecked); |
75 } | 107 } |
76 | 108 |
77 bool BrowserAccessibilityAndroid::IsClickable() const { | 109 bool BrowserAccessibilityAndroid::IsClickable() const { |
78 return (PlatformIsLeaf() && !GetText().empty()); | 110 return (PlatformIsLeaf() && !GetText().empty()); |
79 } | 111 } |
80 | 112 |
| 113 bool BrowserAccessibilityAndroid::IsCollection() const { |
| 114 return (role() == blink::WebAXRoleGrid || |
| 115 role() == blink::WebAXRoleList || |
| 116 role() == blink::WebAXRoleListBox || |
| 117 role() == blink::WebAXRoleTable || |
| 118 role() == blink::WebAXRoleTree); |
| 119 } |
| 120 |
| 121 bool BrowserAccessibilityAndroid::IsCollectionItem() const { |
| 122 return (role() == blink::WebAXRoleCell || |
| 123 role() == blink::WebAXRoleColumnHeader || |
| 124 role() == blink::WebAXRoleDescriptionListTerm || |
| 125 role() == blink::WebAXRoleListBoxOption || |
| 126 role() == blink::WebAXRoleListItem || |
| 127 role() == blink::WebAXRoleRowHeader || |
| 128 role() == blink::WebAXRoleTreeItem); |
| 129 } |
| 130 |
| 131 bool BrowserAccessibilityAndroid::IsContentInvalid() const { |
| 132 std::string invalid; |
| 133 return GetHtmlAttribute("aria-invalid", &invalid); |
| 134 } |
| 135 |
| 136 bool BrowserAccessibilityAndroid::IsDismissable() const { |
| 137 return false; // No concept of "dismissable" on the web currently. |
| 138 } |
| 139 |
81 bool BrowserAccessibilityAndroid::IsEnabled() const { | 140 bool BrowserAccessibilityAndroid::IsEnabled() const { |
82 return HasState(blink::WebAXStateEnabled); | 141 return HasState(blink::WebAXStateEnabled); |
83 } | 142 } |
84 | 143 |
85 bool BrowserAccessibilityAndroid::IsFocusable() const { | 144 bool BrowserAccessibilityAndroid::IsFocusable() const { |
86 bool focusable = HasState(blink::WebAXStateFocusable); | 145 bool focusable = HasState(blink::WebAXStateFocusable); |
87 if (IsIframe() || | 146 if (IsIframe() || |
88 role() == blink::WebAXRoleWebArea) { | 147 role() == blink::WebAXRoleWebArea) { |
89 focusable = false; | 148 focusable = false; |
90 } | 149 } |
91 return focusable; | 150 return focusable; |
92 } | 151 } |
93 | 152 |
94 bool BrowserAccessibilityAndroid::IsFocused() const { | 153 bool BrowserAccessibilityAndroid::IsFocused() const { |
95 return manager()->GetFocus(manager()->GetRoot()) == this; | 154 return manager()->GetFocus(manager()->GetRoot()) == this; |
96 } | 155 } |
97 | 156 |
| 157 bool BrowserAccessibilityAndroid::IsHeading() const { |
| 158 return (role() == blink::WebAXRoleColumnHeader || |
| 159 role() == blink::WebAXRoleHeading || |
| 160 role() == blink::WebAXRoleRowHeader); |
| 161 } |
| 162 |
| 163 bool BrowserAccessibilityAndroid::IsHierarchical() const { |
| 164 return (role() == blink::WebAXRoleList || |
| 165 role() == blink::WebAXRoleTree); |
| 166 } |
| 167 |
| 168 bool BrowserAccessibilityAndroid::IsMultiLine() const { |
| 169 return role() == blink::WebAXRoleTextArea; |
| 170 } |
| 171 |
98 bool BrowserAccessibilityAndroid::IsPassword() const { | 172 bool BrowserAccessibilityAndroid::IsPassword() const { |
99 return HasState(blink::WebAXStateProtected); | 173 return HasState(blink::WebAXStateProtected); |
100 } | 174 } |
101 | 175 |
| 176 bool BrowserAccessibilityAndroid::IsRangeType() const { |
| 177 return (role() == blink::WebAXRoleProgressIndicator || |
| 178 role() == blink::WebAXRoleScrollBar || |
| 179 role() == blink::WebAXRoleSlider); |
| 180 } |
| 181 |
102 bool BrowserAccessibilityAndroid::IsScrollable() const { | 182 bool BrowserAccessibilityAndroid::IsScrollable() const { |
103 int dummy; | 183 int dummy; |
104 return GetIntAttribute(AccessibilityNodeData::ATTR_SCROLL_X_MAX, &dummy); | 184 return GetIntAttribute(AccessibilityNodeData::ATTR_SCROLL_X_MAX, &dummy); |
105 } | 185 } |
106 | 186 |
107 bool BrowserAccessibilityAndroid::IsSelected() const { | 187 bool BrowserAccessibilityAndroid::IsSelected() const { |
108 return HasState(blink::WebAXStateSelected); | 188 return HasState(blink::WebAXStateSelected); |
109 } | 189 } |
110 | 190 |
111 bool BrowserAccessibilityAndroid::IsVisibleToUser() const { | 191 bool BrowserAccessibilityAndroid::IsVisibleToUser() const { |
112 return !HasState(blink::WebAXStateInvisible); | 192 return !HasState(blink::WebAXStateInvisible); |
113 } | 193 } |
114 | 194 |
| 195 bool BrowserAccessibilityAndroid::CanOpenPopup() const { |
| 196 return HasState(blink::WebAXStateHaspopup); |
| 197 } |
| 198 |
115 const char* BrowserAccessibilityAndroid::GetClassName() const { | 199 const char* BrowserAccessibilityAndroid::GetClassName() const { |
116 const char* class_name = NULL; | 200 const char* class_name = NULL; |
117 | 201 |
118 switch(role()) { | 202 switch(role()) { |
119 case blink::WebAXRoleEditableText: | 203 case blink::WebAXRoleEditableText: |
120 case blink::WebAXRoleSpinButton: | 204 case blink::WebAXRoleSpinButton: |
121 case blink::WebAXRoleTextArea: | 205 case blink::WebAXRoleTextArea: |
122 case blink::WebAXRoleTextField: | 206 case blink::WebAXRoleTextField: |
123 class_name = "android.widget.EditText"; | 207 class_name = "android.widget.EditText"; |
124 break; | 208 break; |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
208 } | 292 } |
209 | 293 |
210 return text; | 294 return text; |
211 } | 295 } |
212 | 296 |
213 int BrowserAccessibilityAndroid::GetItemIndex() const { | 297 int BrowserAccessibilityAndroid::GetItemIndex() const { |
214 int index = 0; | 298 int index = 0; |
215 switch(role()) { | 299 switch(role()) { |
216 case blink::WebAXRoleListItem: | 300 case blink::WebAXRoleListItem: |
217 case blink::WebAXRoleListBoxOption: | 301 case blink::WebAXRoleListBoxOption: |
| 302 case blink::WebAXRoleTreeItem: |
218 index = index_in_parent(); | 303 index = index_in_parent(); |
219 break; | 304 break; |
220 case blink::WebAXRoleSlider: | 305 case blink::WebAXRoleSlider: |
221 case blink::WebAXRoleProgressIndicator: { | 306 case blink::WebAXRoleProgressIndicator: { |
222 float value_for_range; | 307 float value_for_range; |
223 if (GetFloatAttribute( | 308 if (GetFloatAttribute( |
224 AccessibilityNodeData::ATTR_VALUE_FOR_RANGE, &value_for_range)) { | 309 AccessibilityNodeData::ATTR_VALUE_FOR_RANGE, &value_for_range)) { |
225 index = static_cast<int>(value_for_range); | 310 index = static_cast<int>(value_for_range); |
226 } | 311 } |
227 break; | 312 break; |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
333 int BrowserAccessibilityAndroid::GetSelectionEnd() const { | 418 int BrowserAccessibilityAndroid::GetSelectionEnd() const { |
334 int sel_end = 0; | 419 int sel_end = 0; |
335 GetIntAttribute(AccessibilityNodeData::ATTR_TEXT_SEL_END, &sel_end); | 420 GetIntAttribute(AccessibilityNodeData::ATTR_TEXT_SEL_END, &sel_end); |
336 return sel_end; | 421 return sel_end; |
337 } | 422 } |
338 | 423 |
339 int BrowserAccessibilityAndroid::GetEditableTextLength() const { | 424 int BrowserAccessibilityAndroid::GetEditableTextLength() const { |
340 return value().length(); | 425 return value().length(); |
341 } | 426 } |
342 | 427 |
| 428 int BrowserAccessibilityAndroid::AndroidInputType() const { |
| 429 std::string html_tag = GetStringAttribute( |
| 430 AccessibilityNodeData::ATTR_HTML_TAG); |
| 431 if (html_tag != "input") |
| 432 return ANDROID_TEXT_INPUTTYPE_TYPE_NULL; |
| 433 |
| 434 std::string type; |
| 435 if (!GetHtmlAttribute("type", &type)) |
| 436 return ANDROID_TEXT_INPUTTYPE_TYPE_TEXT; |
| 437 |
| 438 if (type == "" || type == "text" || type == "search") |
| 439 return ANDROID_TEXT_INPUTTYPE_TYPE_TEXT; |
| 440 else if (type == "date") |
| 441 return ANDROID_TEXT_INPUTTYPE_TYPE_DATETIME_DATE; |
| 442 else if (type == "datetime" || type == "datetime-local") |
| 443 return ANDROID_TEXT_INPUTTYPE_TYPE_DATETIME; |
| 444 else if (type == "email") |
| 445 return ANDROID_TEXT_INPUTTYPE_TYPE_TEXT_WEB_EMAIL; |
| 446 else if (type == "month") |
| 447 return ANDROID_TEXT_INPUTTYPE_TYPE_DATETIME_DATE; |
| 448 else if (type == "number") |
| 449 return ANDROID_TEXT_INPUTTYPE_TYPE_NUMBER; |
| 450 else if (type == "password") |
| 451 return ANDROID_TEXT_INPUTTYPE_TYPE_TEXT_WEB_PASSWORD; |
| 452 else if (type == "tel") |
| 453 return ANDROID_TEXT_INPUTTYPE_TYPE_PHONE; |
| 454 else if (type == "time") |
| 455 return ANDROID_TEXT_INPUTTYPE_TYPE_DATETIME_TIME; |
| 456 else if (type == "url") |
| 457 return ANDROID_TEXT_INPUTTYPE_TYPE_TEXT_URI; |
| 458 else if (type == "week") |
| 459 return ANDROID_TEXT_INPUTTYPE_TYPE_DATETIME; |
| 460 |
| 461 return ANDROID_TEXT_INPUTTYPE_TYPE_NULL; |
| 462 } |
| 463 |
| 464 int BrowserAccessibilityAndroid::AndroidLiveRegionType() const { |
| 465 std::string live = GetStringAttribute( |
| 466 AccessibilityNodeData::ATTR_LIVE_STATUS); |
| 467 if (live == "polite") |
| 468 return ANDROID_VIEW_VIEW_ACCESSIBILITY_LIVE_REGION_POLITE; |
| 469 else if (live == "assertive") |
| 470 return ANDROID_VIEW_VIEW_ACCESSIBILITY_LIVE_REGION_ASSERTIVE; |
| 471 return ANDROID_VIEW_VIEW_ACCESSIBILITY_LIVE_REGION_NONE; |
| 472 } |
| 473 |
| 474 int BrowserAccessibilityAndroid::AndroidRangeType() const { |
| 475 return ANDROID_VIEW_ACCESSIBILITY_RANGE_TYPE_FLOAT; |
| 476 } |
| 477 |
| 478 int BrowserAccessibilityAndroid::RowCount() const { |
| 479 if (role() == blink::WebAXRoleGrid || |
| 480 role() == blink::WebAXRoleTable) { |
| 481 return CountChildrenWithRole(blink::WebAXRoleRow); |
| 482 } |
| 483 |
| 484 if (role() == blink::WebAXRoleList || |
| 485 role() == blink::WebAXRoleListBox || |
| 486 role() == blink::WebAXRoleTree) { |
| 487 return PlatformChildCount(); |
| 488 } |
| 489 |
| 490 return 0; |
| 491 } |
| 492 |
| 493 int BrowserAccessibilityAndroid::ColumnCount() const { |
| 494 if (role() == blink::WebAXRoleGrid || |
| 495 role() == blink::WebAXRoleTable) { |
| 496 return CountChildrenWithRole(blink::WebAXRoleColumn); |
| 497 } |
| 498 return 0; |
| 499 } |
| 500 |
| 501 int BrowserAccessibilityAndroid::RowIndex() const { |
| 502 if (role() == blink::WebAXRoleListItem || |
| 503 role() == blink::WebAXRoleListBoxOption || |
| 504 role() == blink::WebAXRoleTreeItem) { |
| 505 return index_in_parent(); |
| 506 } |
| 507 |
| 508 return GetIntAttribute(AccessibilityNodeData::ATTR_TABLE_CELL_ROW_INDEX); |
| 509 } |
| 510 |
| 511 int BrowserAccessibilityAndroid::RowSpan() const { |
| 512 return GetIntAttribute(AccessibilityNodeData::ATTR_TABLE_CELL_ROW_SPAN); |
| 513 } |
| 514 |
| 515 int BrowserAccessibilityAndroid::ColumnIndex() const { |
| 516 return GetIntAttribute(AccessibilityNodeData::ATTR_TABLE_CELL_COLUMN_INDEX); |
| 517 } |
| 518 |
| 519 int BrowserAccessibilityAndroid::ColumnSpan() const { |
| 520 return GetIntAttribute(AccessibilityNodeData::ATTR_TABLE_CELL_COLUMN_SPAN); |
| 521 } |
| 522 |
| 523 float BrowserAccessibilityAndroid::RangeMin() const { |
| 524 return GetFloatAttribute(AccessibilityNodeData::ATTR_MIN_VALUE_FOR_RANGE); |
| 525 } |
| 526 |
| 527 float BrowserAccessibilityAndroid::RangeMax() const { |
| 528 return GetFloatAttribute(AccessibilityNodeData::ATTR_MAX_VALUE_FOR_RANGE); |
| 529 } |
| 530 |
| 531 float BrowserAccessibilityAndroid::RangeCurrentValue() const { |
| 532 return GetFloatAttribute(AccessibilityNodeData::ATTR_VALUE_FOR_RANGE); |
| 533 } |
| 534 |
343 bool BrowserAccessibilityAndroid::HasFocusableChild() const { | 535 bool BrowserAccessibilityAndroid::HasFocusableChild() const { |
344 // This is called from PlatformIsLeaf, so don't call PlatformChildCount | 536 // This is called from PlatformIsLeaf, so don't call PlatformChildCount |
345 // from within this! | 537 // from within this! |
346 for (uint32 i = 0; i < child_count(); i++) { | 538 for (uint32 i = 0; i < child_count(); i++) { |
347 BrowserAccessibility* child = children()[i]; | 539 BrowserAccessibility* child = children()[i]; |
348 if (child->HasState(blink::WebAXStateFocusable)) | 540 if (child->HasState(blink::WebAXStateFocusable)) |
349 return true; | 541 return true; |
350 if (static_cast<BrowserAccessibilityAndroid*>(child)->HasFocusableChild()) | 542 if (static_cast<BrowserAccessibilityAndroid*>(child)->HasFocusableChild()) |
351 return true; | 543 return true; |
352 } | 544 } |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
401 base::string16 text = GetText(); | 593 base::string16 text = GetText(); |
402 if (cached_text_ != text) { | 594 if (cached_text_ != text) { |
403 if (!text.empty()) { | 595 if (!text.empty()) { |
404 manager()->NotifyAccessibilityEvent(blink::WebAXEventShow, | 596 manager()->NotifyAccessibilityEvent(blink::WebAXEventShow, |
405 this); | 597 this); |
406 } | 598 } |
407 cached_text_ = text; | 599 cached_text_ = text; |
408 } | 600 } |
409 } | 601 } |
410 | 602 |
| 603 int BrowserAccessibilityAndroid::CountChildrenWithRole( |
| 604 blink::WebAXRole role) const { |
| 605 int count = 0; |
| 606 for (uint32 i = 0; i < PlatformChildCount(); i++) { |
| 607 if (PlatformGetChild(i)->role() == role) |
| 608 count++; |
| 609 } |
| 610 return count; |
| 611 } |
| 612 |
411 } // namespace content | 613 } // namespace content |
OLD | NEW |