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

Side by Side Diff: content/browser/accessibility/browser_accessibility_manager_android.cc

Issue 1767313002: TalkBack needs to know supported HTML element types (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Alternate approach Created 4 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
OLDNEW
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_manager_android.h" 5 #include "content/browser/accessibility/browser_accessibility_manager_android.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <cmath> 9 #include <cmath>
10 10
11 #include "base/android/jni_android.h" 11 #include "base/android/jni_android.h"
12 #include "base/android/jni_string.h" 12 #include "base/android/jni_string.h"
13 #include "base/i18n/char_iterator.h" 13 #include "base/i18n/char_iterator.h"
14 #include "base/strings/string_number_conversions.h" 14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/utf_string_conversions.h" 15 #include "base/strings/utf_string_conversions.h"
16 #include "base/values.h" 16 #include "base/values.h"
17 #include "content/browser/accessibility/browser_accessibility_android.h" 17 #include "content/browser/accessibility/browser_accessibility_android.h"
18 #include "content/browser/accessibility/one_shot_accessibility_tree_search.h" 18 #include "content/browser/accessibility/one_shot_accessibility_tree_search.h"
19 #include "content/common/accessibility_messages.h" 19 #include "content/common/accessibility_messages.h"
20 #include "jni/BrowserAccessibilityManager_jni.h" 20 #include "jni/BrowserAccessibilityManager_jni.h"
21 #include "ui/accessibility/ax_text_utils.h" 21 #include "ui/accessibility/ax_text_utils.h"
22 22
23 using base::android::AttachCurrentThread; 23 using base::android::AttachCurrentThread;
24 using base::android::ScopedJavaLocalRef; 24 using base::android::ScopedJavaLocalRef;
25 25
26 namespace content { 26 namespace content {
27 27
28 namespace { 28 namespace {
29 29
30 using SearchKeyToPredicateMap =
31 base::hash_map<base::string16, AccessibilityMatchPredicate>;
32 base::LazyInstance<SearchKeyToPredicateMap> g_search_key_to_predicate_map =
33 LAZY_INSTANCE_INITIALIZER;
34 base::LazyInstance<base::string16> g_all_search_keys =
35 LAZY_INSTANCE_INITIALIZER;
36
37 bool SectionPredicate(
38 BrowserAccessibility* start, BrowserAccessibility* node) {
39 switch (node->GetRole()) {
40 case ui::AX_ROLE_ARTICLE:
41 case ui::AX_ROLE_APPLICATION:
42 case ui::AX_ROLE_BANNER:
43 case ui::AX_ROLE_COMPLEMENTARY:
44 case ui::AX_ROLE_CONTENT_INFO:
45 case ui::AX_ROLE_HEADING:
46 case ui::AX_ROLE_MAIN:
47 case ui::AX_ROLE_NAVIGATION:
48 case ui::AX_ROLE_SEARCH:
49 case ui::AX_ROLE_REGION:
50 return true;
51 default:
52 return false;
53 }
54 }
55
56 void AddToPredicateMap(const char* search_key_ascii,
57 AccessibilityMatchPredicate predicate) {
58 base::string16 search_key_utf16 = base::ASCIIToUTF16(search_key_ascii);
59 g_search_key_to_predicate_map.Get()[search_key_utf16] = predicate;
60 if (!g_all_search_keys.Get().empty())
61 g_all_search_keys.Get() += base::ASCIIToUTF16(",");
62 g_all_search_keys.Get() += search_key_utf16;
63 }
64
30 // These are special unofficial strings sent from TalkBack/BrailleBack 65 // These are special unofficial strings sent from TalkBack/BrailleBack
31 // to jump to certain categories of web elements. 66 // to jump to certain categories of web elements.
32 AccessibilityMatchPredicate PredicateForSearchKey(base::string16 element_type) { 67 void InitSearchKeyToPredicateMapIfNeeded() {
33 if (element_type == base::ASCIIToUTF16("SECTION")) { 68 if (!g_search_key_to_predicate_map.Get().empty())
34 return [](BrowserAccessibility* start, BrowserAccessibility* node) { 69 return;
35 switch (node->GetRole()) { 70
36 case ui::AX_ROLE_ARTICLE: 71 AddToPredicateMap("ARTICLE", AccessibilityArticlePredicate);
37 case ui::AX_ROLE_APPLICATION: 72 AddToPredicateMap("BUTTON", AccessibilityButtonPredicate);
38 case ui::AX_ROLE_BANNER: 73 AddToPredicateMap("CHECKBOX", AccessibilityCheckboxPredicate);
39 case ui::AX_ROLE_COMPLEMENTARY: 74 AddToPredicateMap("COMBOBOX", AccessibilityComboboxPredicate);
40 case ui::AX_ROLE_CONTENT_INFO: 75 AddToPredicateMap("CONTROL", AccessibilityControlPredicate);
41 case ui::AX_ROLE_HEADING: 76 AddToPredicateMap("FOCUSABLE", AccessibilityFocusablePredicate);
42 case ui::AX_ROLE_MAIN: 77 AddToPredicateMap("FRAME", AccessibilityFramePredicate);
43 case ui::AX_ROLE_NAVIGATION: 78 AddToPredicateMap("GRAPHIC", AccessibilityGraphicPredicate);
44 case ui::AX_ROLE_SEARCH: 79 AddToPredicateMap("H1", AccessibilityH1Predicate);
45 case ui::AX_ROLE_REGION: 80 AddToPredicateMap("H2", AccessibilityH2Predicate);
46 return true; 81 AddToPredicateMap("H3", AccessibilityH3Predicate);
47 default: 82 AddToPredicateMap("H4", AccessibilityH4Predicate);
48 return false; 83 AddToPredicateMap("H5", AccessibilityH5Predicate);
49 } 84 AddToPredicateMap("H6", AccessibilityH6Predicate);
50 }; 85 AddToPredicateMap("HEADING", AccessibilityHeadingPredicate);
51 } else if (element_type == base::ASCIIToUTF16("LIST")) { 86 AddToPredicateMap("LANDMARK", AccessibilityLandmarkPredicate);
52 return AccessibilityListPredicate; 87 AddToPredicateMap("LINK", AccessibilityLinkPredicate);
53 } else if (element_type == base::ASCIIToUTF16("CONTROL")) { 88 AddToPredicateMap("LIST", AccessibilityListPredicate);
54 return AccessibilityControlPredicate; 89 AddToPredicateMap("LIST_ITEM", AccessibilityListItemPredicate);
55 } else if (element_type == base::ASCIIToUTF16("ARTICLE")) { 90 AddToPredicateMap("MAIN", AccessibilityMainPredicate);
56 return AccessibilityArticlePredicate; 91 AddToPredicateMap("MEDIA", AccessibilityMediaPredicate);
57 } else if (element_type == base::ASCIIToUTF16("BUTTON")) { 92 AddToPredicateMap("RADIO", AccessibilityRadioButtonPredicate);
58 return AccessibilityButtonPredicate; 93 AddToPredicateMap("SECTION", SectionPredicate);
59 } else if (element_type == base::ASCIIToUTF16("CHECKBOX")) { 94 AddToPredicateMap("TABLE", AccessibilityTablePredicate);
60 return AccessibilityCheckboxPredicate; 95 AddToPredicateMap("TEXT_FIELD", AccessibilityTextfieldPredicate);
61 } else if (element_type == base::ASCIIToUTF16("COMBOBOX")) { 96 AddToPredicateMap("UNVISITED_LINK", AccessibilityUnvisitedLinkPredicate);
62 return AccessibilityComboboxPredicate; 97 AddToPredicateMap("VISITED_LINK", AccessibilityVisitedLinkPredicate);
63 } else if (element_type == base::ASCIIToUTF16("TEXT_FIELD")) { 98 }
64 return AccessibilityTextfieldPredicate; 99
65 } else if (element_type == base::ASCIIToUTF16("FOCUSABLE")) { 100 AccessibilityMatchPredicate PredicateForSearchKey(
66 return AccessibilityFocusablePredicate; 101 const base::string16& element_type) {
67 } else if (element_type == base::ASCIIToUTF16("GRAPHIC")) { 102 InitSearchKeyToPredicateMapIfNeeded();
68 return AccessibilityGraphicPredicate; 103 const auto& iter = g_search_key_to_predicate_map.Get().find(element_type);
69 } else if (element_type == base::ASCIIToUTF16("HEADING")) { 104 if (iter != g_search_key_to_predicate_map.Get().end())
70 return AccessibilityHeadingPredicate; 105 return iter->second;
71 } else if (element_type == base::ASCIIToUTF16("H1")) {
72 return AccessibilityH1Predicate;
73 } else if (element_type == base::ASCIIToUTF16("H2")) {
74 return AccessibilityH2Predicate;
75 } else if (element_type == base::ASCIIToUTF16("H3")) {
76 return AccessibilityH3Predicate;
77 } else if (element_type == base::ASCIIToUTF16("H4")) {
78 return AccessibilityH4Predicate;
79 } else if (element_type == base::ASCIIToUTF16("H5")) {
80 return AccessibilityH5Predicate;
81 } else if (element_type == base::ASCIIToUTF16("H6")) {
82 return AccessibilityH6Predicate;
83 } else if (element_type == base::ASCIIToUTF16("FRAME")) {
84 return AccessibilityFramePredicate;
85 } else if (element_type == base::ASCIIToUTF16("LANDMARK")) {
86 return AccessibilityLandmarkPredicate;
87 } else if (element_type == base::ASCIIToUTF16("LINK")) {
88 return AccessibilityLinkPredicate;
89 } else if (element_type == base::ASCIIToUTF16("LIST_ITEM")) {
90 return AccessibilityListItemPredicate;
91 } else if (element_type == base::ASCIIToUTF16("MAIN")) {
92 return AccessibilityMainPredicate;
93 } else if (element_type == base::ASCIIToUTF16("MEDIA")) {
94 return AccessibilityMediaPredicate;
95 } else if (element_type == base::ASCIIToUTF16("RADIO")) {
96 return AccessibilityRadioButtonPredicate;
97 } else if (element_type == base::ASCIIToUTF16("TABLE")) {
98 return AccessibilityTablePredicate;
99 } else if (element_type == base::ASCIIToUTF16("UNVISITED_LINK")) {
100 return AccessibilityUnvisitedLinkPredicate;
101 } else if (element_type == base::ASCIIToUTF16("VISITED_LINK")) {
102 return AccessibilityVisitedLinkPredicate;
103 }
104 106
105 // If we don't recognize the selector, return any element that's clickable. 107 // If we don't recognize the selector, return any element that's clickable.
106 // We mark all focusable nodes and leaf nodes as clickable because it's 108 // We mark all focusable nodes and leaf nodes as clickable because it's
107 // impossible to know whether a web node has a click handler or not, so 109 // impossible to know whether a web node has a click handler or not, so
108 // to be safe we have to allow accessibility services to click on nearly 110 // to be safe we have to allow accessibility services to click on nearly
109 // anything that could possibly respond to a click. 111 // anything that could possibly respond to a click.
110 return [](BrowserAccessibility* start, BrowserAccessibility* node) { 112 return [](BrowserAccessibility* start, BrowserAccessibility* node) {
111 return static_cast<BrowserAccessibilityAndroid*>(node)->IsClickable(); 113 return static_cast<BrowserAccessibilityAndroid*>(node)->IsClickable();
112 }; 114 };
113 } 115 }
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
280 if (obj.is_null()) 282 if (obj.is_null())
281 return; 283 return;
282 Java_BrowserAccessibilityManager_sendDelayedWindowContentChangedEvent( 284 Java_BrowserAccessibilityManager_sendDelayedWindowContentChangedEvent(
283 env, obj.obj()); 285 env, obj.obj());
284 return; 286 return;
285 } 287 }
286 288
287 BrowserAccessibilityManager::OnLocationChanges(params); 289 BrowserAccessibilityManager::OnLocationChanges(params);
288 } 290 }
289 291
292 base::android::ScopedJavaLocalRef<jstring>
293 BrowserAccessibilityManagerAndroid::GetSupportedHtmlElementTypes(
294 JNIEnv* env,
295 const JavaParamRef<jobject>& obj) {
296 InitSearchKeyToPredicateMapIfNeeded();
297 return base::android::ConvertUTF16ToJavaString(env, g_all_search_keys.Get());
298 }
299
290 jint BrowserAccessibilityManagerAndroid::GetRootId( 300 jint BrowserAccessibilityManagerAndroid::GetRootId(
291 JNIEnv* env, 301 JNIEnv* env,
292 const JavaParamRef<jobject>& obj) { 302 const JavaParamRef<jobject>& obj) {
293 if (GetRoot()) 303 if (GetRoot())
294 return static_cast<jint>(GetRoot()->GetId()); 304 return static_cast<jint>(GetRoot()->GetId());
295 else 305 else
296 return -1; 306 return -1;
297 } 307 }
298 308
299 jboolean BrowserAccessibilityManagerAndroid::IsNodeValid( 309 jboolean BrowserAccessibilityManagerAndroid::IsNodeValid(
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
420 Java_BrowserAccessibilityManager_setAccessibilityNodeInfoLocation( 430 Java_BrowserAccessibilityManager_setAccessibilityNodeInfoLocation(
421 env, obj, info, 431 env, obj, info,
422 id, 432 id,
423 absolute_rect.x(), absolute_rect.y(), 433 absolute_rect.x(), absolute_rect.y(),
424 parent_relative_rect.x(), parent_relative_rect.y(), 434 parent_relative_rect.x(), parent_relative_rect.y(),
425 absolute_rect.width(), absolute_rect.height(), 435 absolute_rect.width(), absolute_rect.height(),
426 is_root); 436 is_root);
427 437
428 Java_BrowserAccessibilityManager_setAccessibilityNodeInfoKitKatAttributes( 438 Java_BrowserAccessibilityManager_setAccessibilityNodeInfoKitKatAttributes(
429 env, obj, info, 439 env, obj, info,
440 is_root,
430 base::android::ConvertUTF16ToJavaString( 441 base::android::ConvertUTF16ToJavaString(
431 env, node->GetRoleDescription()).obj()); 442 env, node->GetRoleDescription()).obj());
432 443
433 Java_BrowserAccessibilityManager_setAccessibilityNodeInfoLollipopAttributes( 444 Java_BrowserAccessibilityManager_setAccessibilityNodeInfoLollipopAttributes(
434 env, obj, info, 445 env, obj, info,
435 node->CanOpenPopup(), 446 node->CanOpenPopup(),
436 node->IsContentInvalid(), 447 node->IsContentInvalid(),
437 node->IsDismissable(), 448 node->IsDismissable(),
438 node->IsMultiLine(), 449 node->IsMultiLine(),
439 node->AndroidInputType(), 450 node->AndroidInputType(),
(...skipping 479 matching lines...) Expand 10 before | Expand all | Expand 10 after
919 BrowserAccessibilityManagerAndroid::UseRootScrollOffsetsWhenComputingBounds() { 930 BrowserAccessibilityManagerAndroid::UseRootScrollOffsetsWhenComputingBounds() {
920 // The Java layer handles the root scroll offset. 931 // The Java layer handles the root scroll offset.
921 return false; 932 return false;
922 } 933 }
923 934
924 bool RegisterBrowserAccessibilityManager(JNIEnv* env) { 935 bool RegisterBrowserAccessibilityManager(JNIEnv* env) {
925 return RegisterNativesImpl(env); 936 return RegisterNativesImpl(env);
926 } 937 }
927 938
928 } // namespace content 939 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698