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/i18n/break_iterator.h" | 7 #include "base/i18n/break_iterator.h" |
8 #include "base/strings/string_number_conversions.h" | 8 #include "base/strings/string_number_conversions.h" |
9 #include "base/strings/string_util.h" | 9 #include "base/strings/string_util.h" |
10 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
11 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
12 #include "content/app/strings/grit/content_strings.h" | 12 #include "content/app/strings/grit/content_strings.h" |
13 #include "content/browser/accessibility/browser_accessibility_manager_android.h" | 13 #include "content/browser/accessibility/browser_accessibility_manager_android.h" |
14 #include "content/common/accessibility_messages.h" | 14 #include "content/common/accessibility_messages.h" |
15 #include "content/public/common/content_client.h" | 15 #include "content/public/common/content_client.h" |
16 #include "third_party/skia/include/core/SkColor.h" | 16 #include "third_party/skia/include/core/SkColor.h" |
17 #include "ui/accessibility/platform/ax_android_constants.h" | 17 #include "ui/accessibility/platform/ax_android_constants.h" |
| 18 #include "ui/accessibility/platform/ax_snapshot_node_android_platform.h" |
18 | 19 |
19 namespace { | 20 namespace { |
20 | 21 |
21 const base::char16 kSecurePasswordBullet = 0x2022; | |
22 | |
23 // These are enums from android.text.InputType in Java: | 22 // These are enums from android.text.InputType in Java: |
24 enum { | 23 enum { |
25 ANDROID_TEXT_INPUTTYPE_TYPE_NULL = 0, | 24 ANDROID_TEXT_INPUTTYPE_TYPE_NULL = 0, |
26 ANDROID_TEXT_INPUTTYPE_TYPE_DATETIME = 0x4, | 25 ANDROID_TEXT_INPUTTYPE_TYPE_DATETIME = 0x4, |
27 ANDROID_TEXT_INPUTTYPE_TYPE_DATETIME_DATE = 0x14, | 26 ANDROID_TEXT_INPUTTYPE_TYPE_DATETIME_DATE = 0x14, |
28 ANDROID_TEXT_INPUTTYPE_TYPE_DATETIME_TIME = 0x24, | 27 ANDROID_TEXT_INPUTTYPE_TYPE_DATETIME_TIME = 0x24, |
29 ANDROID_TEXT_INPUTTYPE_TYPE_NUMBER = 0x2, | 28 ANDROID_TEXT_INPUTTYPE_TYPE_NUMBER = 0x2, |
30 ANDROID_TEXT_INPUTTYPE_TYPE_PHONE = 0x3, | 29 ANDROID_TEXT_INPUTTYPE_TYPE_PHONE = 0x3, |
31 ANDROID_TEXT_INPUTTYPE_TYPE_TEXT = 0x1, | 30 ANDROID_TEXT_INPUTTYPE_TYPE_TEXT = 0x1, |
32 ANDROID_TEXT_INPUTTYPE_TYPE_TEXT_URI = 0x11, | 31 ANDROID_TEXT_INPUTTYPE_TYPE_TEXT_URI = 0x11, |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
74 | 73 |
75 base::string16 BrowserAccessibilityAndroid::GetValue() const { | 74 base::string16 BrowserAccessibilityAndroid::GetValue() const { |
76 base::string16 value = BrowserAccessibility::GetValue(); | 75 base::string16 value = BrowserAccessibility::GetValue(); |
77 | 76 |
78 // Optionally replace entered password text with bullet characters | 77 // Optionally replace entered password text with bullet characters |
79 // based on a user preference. | 78 // based on a user preference. |
80 if (IsPassword()) { | 79 if (IsPassword()) { |
81 bool should_expose = static_cast<BrowserAccessibilityManagerAndroid*>( | 80 bool should_expose = static_cast<BrowserAccessibilityManagerAndroid*>( |
82 manager())->ShouldExposePasswordText(); | 81 manager())->ShouldExposePasswordText(); |
83 if (!should_expose) { | 82 if (!should_expose) { |
84 value = base::string16(value.size(), kSecurePasswordBullet); | 83 value = base::string16(value.size(), ui::kSecurePasswordBullet); |
85 } | 84 } |
86 } | 85 } |
87 | 86 |
88 return value; | 87 return value; |
89 } | 88 } |
90 | 89 |
91 bool BrowserAccessibilityAndroid::PlatformIsLeaf() const { | 90 bool BrowserAccessibilityAndroid::PlatformIsLeaf() const { |
92 if (BrowserAccessibility::PlatformIsLeaf()) | 91 if (BrowserAccessibility::PlatformIsLeaf()) |
93 return true; | 92 return true; |
94 | 93 |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
238 GetRole() == ui::AX_ROLE_ROW_HEADER); | 237 GetRole() == ui::AX_ROLE_ROW_HEADER); |
239 } | 238 } |
240 | 239 |
241 bool BrowserAccessibilityAndroid::IsHierarchical() const { | 240 bool BrowserAccessibilityAndroid::IsHierarchical() const { |
242 return (GetRole() == ui::AX_ROLE_LIST || | 241 return (GetRole() == ui::AX_ROLE_LIST || |
243 GetRole() == ui::AX_ROLE_DESCRIPTION_LIST || | 242 GetRole() == ui::AX_ROLE_DESCRIPTION_LIST || |
244 GetRole() == ui::AX_ROLE_TREE); | 243 GetRole() == ui::AX_ROLE_TREE); |
245 } | 244 } |
246 | 245 |
247 bool BrowserAccessibilityAndroid::IsLink() const { | 246 bool BrowserAccessibilityAndroid::IsLink() const { |
248 return (GetRole() == ui::AX_ROLE_LINK || | 247 return ui::AXSnapshotNodeAndroid::AXRoleIsLink(GetRole()); |
249 GetRole() == ui::AX_ROLE_IMAGE_MAP_LINK); | |
250 } | 248 } |
251 | 249 |
252 bool BrowserAccessibilityAndroid::IsMultiLine() const { | 250 bool BrowserAccessibilityAndroid::IsMultiLine() const { |
253 return HasState(ui::AX_STATE_MULTILINE); | 251 return HasState(ui::AX_STATE_MULTILINE); |
254 } | 252 } |
255 | 253 |
256 bool BrowserAccessibilityAndroid::IsPassword() const { | 254 bool BrowserAccessibilityAndroid::IsPassword() const { |
257 return HasState(ui::AX_STATE_PROTECTED); | 255 return HasState(ui::AX_STATE_PROTECTED); |
258 } | 256 } |
259 | 257 |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
321 } | 319 } |
322 | 320 |
323 return sole_interesting_node; | 321 return sole_interesting_node; |
324 } | 322 } |
325 | 323 |
326 bool BrowserAccessibilityAndroid::CanOpenPopup() const { | 324 bool BrowserAccessibilityAndroid::CanOpenPopup() const { |
327 return HasState(ui::AX_STATE_HASPOPUP); | 325 return HasState(ui::AX_STATE_HASPOPUP); |
328 } | 326 } |
329 | 327 |
330 const char* BrowserAccessibilityAndroid::GetClassName() const { | 328 const char* BrowserAccessibilityAndroid::GetClassName() const { |
331 const char* class_name = NULL; | 329 return ui::AXSnapshotNodeAndroid::AXRoleToAndroidClassName( |
332 | 330 GetRole(), PlatformGetParent() != nullptr); |
333 switch (GetRole()) { | |
334 case ui::AX_ROLE_SEARCH_BOX: | |
335 case ui::AX_ROLE_SPIN_BUTTON: | |
336 case ui::AX_ROLE_TEXT_FIELD: | |
337 class_name = ui::kAXEditTextClassname; | |
338 break; | |
339 case ui::AX_ROLE_SLIDER: | |
340 class_name = ui::kAXSeekBarClassname; | |
341 break; | |
342 case ui::AX_ROLE_COLOR_WELL: | |
343 case ui::AX_ROLE_COMBO_BOX: | |
344 case ui::AX_ROLE_DATE: | |
345 case ui::AX_ROLE_POP_UP_BUTTON: | |
346 case ui::AX_ROLE_INPUT_TIME: | |
347 class_name = ui::kAXSpinnerClassname; | |
348 break; | |
349 case ui::AX_ROLE_BUTTON: | |
350 case ui::AX_ROLE_MENU_BUTTON: | |
351 class_name = ui::kAXButtonClassname; | |
352 break; | |
353 case ui::AX_ROLE_CHECK_BOX: | |
354 case ui::AX_ROLE_SWITCH: | |
355 class_name = ui::kAXCheckBoxClassname; | |
356 break; | |
357 case ui::AX_ROLE_RADIO_BUTTON: | |
358 class_name = ui::kAXRadioButtonClassname; | |
359 break; | |
360 case ui::AX_ROLE_TOGGLE_BUTTON: | |
361 class_name = ui::kAXToggleButtonClassname; | |
362 break; | |
363 case ui::AX_ROLE_CANVAS: | |
364 case ui::AX_ROLE_IMAGE: | |
365 case ui::AX_ROLE_SVG_ROOT: | |
366 class_name = ui::kAXImageClassname; | |
367 break; | |
368 case ui::AX_ROLE_METER: | |
369 case ui::AX_ROLE_PROGRESS_INDICATOR: | |
370 class_name = ui::kAXProgressBarClassname; | |
371 break; | |
372 case ui::AX_ROLE_TAB_LIST: | |
373 class_name = ui::kAXTabWidgetClassname; | |
374 break; | |
375 case ui::AX_ROLE_GRID: | |
376 case ui::AX_ROLE_TREE_GRID: | |
377 case ui::AX_ROLE_TABLE: | |
378 class_name = ui::kAXGridViewClassname; | |
379 break; | |
380 case ui::AX_ROLE_LIST: | |
381 case ui::AX_ROLE_LIST_BOX: | |
382 case ui::AX_ROLE_DESCRIPTION_LIST: | |
383 class_name = ui::kAXListViewClassname; | |
384 break; | |
385 case ui::AX_ROLE_DIALOG: | |
386 class_name = ui::kAXDialogClassname; | |
387 break; | |
388 case ui::AX_ROLE_ROOT_WEB_AREA: | |
389 if (PlatformGetParent() == nullptr) | |
390 class_name = ui::kAXWebViewClassname; | |
391 else | |
392 class_name = ui::kAXViewClassname; | |
393 break; | |
394 case ui::AX_ROLE_MENU_ITEM: | |
395 case ui::AX_ROLE_MENU_ITEM_CHECK_BOX: | |
396 case ui::AX_ROLE_MENU_ITEM_RADIO: | |
397 class_name = ui::kAXMenuItemClassname; | |
398 break; | |
399 default: | |
400 class_name = ui::kAXViewClassname; | |
401 break; | |
402 } | |
403 | |
404 return class_name; | |
405 } | 331 } |
406 | 332 |
407 base::string16 BrowserAccessibilityAndroid::GetText() const { | 333 base::string16 BrowserAccessibilityAndroid::GetText() const { |
408 if (IsIframe() || | 334 if (IsIframe() || |
409 GetRole() == ui::AX_ROLE_WEB_AREA) { | 335 GetRole() == ui::AX_ROLE_WEB_AREA) { |
410 return base::string16(); | 336 return base::string16(); |
411 } | 337 } |
412 | 338 |
413 // In accordance with ARIA, some elements use their contents as an | 339 // In accordance with ARIA, some elements use their contents as an |
414 // accessibility name, so some elements will have the same name as their | 340 // accessibility name, so some elements will have the same name as their |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
477 if (text.empty() && (HasOnlyTextChildren() || | 403 if (text.empty() && (HasOnlyTextChildren() || |
478 (IsFocusable() && HasOnlyTextAndImageChildren()))) { | 404 (IsFocusable() && HasOnlyTextAndImageChildren()))) { |
479 for (uint32_t i = 0; i < InternalChildCount(); i++) { | 405 for (uint32_t i = 0; i < InternalChildCount(); i++) { |
480 BrowserAccessibility* child = InternalGetChild(i); | 406 BrowserAccessibility* child = InternalGetChild(i); |
481 text += static_cast<BrowserAccessibilityAndroid*>(child)->GetText(); | 407 text += static_cast<BrowserAccessibilityAndroid*>(child)->GetText(); |
482 } | 408 } |
483 } | 409 } |
484 | 410 |
485 if (text.empty() && (IsLink() || GetRole() == ui::AX_ROLE_IMAGE)) { | 411 if (text.empty() && (IsLink() || GetRole() == ui::AX_ROLE_IMAGE)) { |
486 base::string16 url = GetString16Attribute(ui::AX_ATTR_URL); | 412 base::string16 url = GetString16Attribute(ui::AX_ATTR_URL); |
487 // Given a url like http://foo.com/bar/baz.png, just return the | 413 text = ui::AXSnapshotNodeAndroid::AXUrlBaseText(url); |
488 // base text, e.g., "baz". | |
489 int trailing_slashes = 0; | |
490 while (url.size() - trailing_slashes > 0 && | |
491 url[url.size() - trailing_slashes - 1] == '/') { | |
492 trailing_slashes++; | |
493 } | |
494 if (trailing_slashes) | |
495 url = url.substr(0, url.size() - trailing_slashes); | |
496 size_t slash_index = url.rfind('/'); | |
497 if (slash_index != std::string::npos) | |
498 url = url.substr(slash_index + 1); | |
499 size_t dot_index = url.rfind('.'); | |
500 if (dot_index != std::string::npos) | |
501 url = url.substr(0, dot_index); | |
502 text = url; | |
503 } | 414 } |
504 | 415 |
505 return text; | 416 return text; |
506 } | 417 } |
507 | 418 |
508 base::string16 BrowserAccessibilityAndroid::GetRoleDescription() const { | 419 base::string16 BrowserAccessibilityAndroid::GetRoleDescription() const { |
509 content::ContentClient* content_client = content::GetContentClient(); | 420 content::ContentClient* content_client = content::GetContentClient(); |
510 | 421 |
511 // As a special case, if we have a heading level return a string like | 422 // As a special case, if we have a heading level return a string like |
512 // "heading level 1", etc. | 423 // "heading level 1", etc. |
(...skipping 991 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1504 int BrowserAccessibilityAndroid::CountChildrenWithRole(ui::AXRole role) const { | 1415 int BrowserAccessibilityAndroid::CountChildrenWithRole(ui::AXRole role) const { |
1505 int count = 0; | 1416 int count = 0; |
1506 for (uint32_t i = 0; i < PlatformChildCount(); i++) { | 1417 for (uint32_t i = 0; i < PlatformChildCount(); i++) { |
1507 if (PlatformGetChild(i)->GetRole() == role) | 1418 if (PlatformGetChild(i)->GetRole() == role) |
1508 count++; | 1419 count++; |
1509 } | 1420 } |
1510 return count; | 1421 return count; |
1511 } | 1422 } |
1512 | 1423 |
1513 } // namespace content | 1424 } // namespace content |
OLD | NEW |