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_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/feature_list.h" |
13 #include "base/i18n/char_iterator.h" | 14 #include "base/i18n/char_iterator.h" |
14 #include "base/strings/string_number_conversions.h" | 15 #include "base/strings/string_number_conversions.h" |
15 #include "base/strings/utf_string_conversions.h" | 16 #include "base/strings/utf_string_conversions.h" |
16 #include "base/values.h" | 17 #include "base/values.h" |
| 18 #include "content/app/strings/grit/content_strings.h" |
17 #include "content/browser/accessibility/browser_accessibility_android.h" | 19 #include "content/browser/accessibility/browser_accessibility_android.h" |
18 #include "content/browser/accessibility/one_shot_accessibility_tree_search.h" | 20 #include "content/browser/accessibility/one_shot_accessibility_tree_search.h" |
19 #include "content/common/accessibility_messages.h" | 21 #include "content/common/accessibility_messages.h" |
| 22 #include "content/public/common/content_features.h" |
20 #include "jni/BrowserAccessibilityManager_jni.h" | 23 #include "jni/BrowserAccessibilityManager_jni.h" |
21 #include "ui/accessibility/ax_text_utils.h" | 24 #include "ui/accessibility/ax_text_utils.h" |
22 | 25 |
23 using base::android::AttachCurrentThread; | 26 using base::android::AttachCurrentThread; |
24 using base::android::JavaParamRef; | 27 using base::android::JavaParamRef; |
25 using base::android::ScopedJavaLocalRef; | 28 using base::android::ScopedJavaLocalRef; |
26 | 29 |
27 namespace content { | 30 namespace content { |
28 | 31 |
29 namespace { | 32 namespace { |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
110 InitSearchKeyToPredicateMapIfNeeded(); | 113 InitSearchKeyToPredicateMapIfNeeded(); |
111 const auto& iter = g_search_key_to_predicate_map.Get().find(element_type); | 114 const auto& iter = g_search_key_to_predicate_map.Get().find(element_type); |
112 if (iter != g_search_key_to_predicate_map.Get().end()) | 115 if (iter != g_search_key_to_predicate_map.Get().end()) |
113 return iter->second; | 116 return iter->second; |
114 | 117 |
115 // If we don't recognize the selector, return any element that a | 118 // If we don't recognize the selector, return any element that a |
116 // screen reader should navigate to. | 119 // screen reader should navigate to. |
117 return AllInterestingNodesPredicate; | 120 return AllInterestingNodesPredicate; |
118 } | 121 } |
119 | 122 |
| 123 // The element in the document for which we may be displaying an autofill popup. |
| 124 int32_t g_element_hosting_autofill_popup_unique_id = -1; |
| 125 |
| 126 // Autofill popup will not be part of the |AXTree| that is sent by renderer. |
| 127 // Hence, we need a proxy |AXNode| to represent the autofill popup. |
| 128 BrowserAccessibility* g_autofill_popup_proxy_node = nullptr; |
| 129 ui::AXNode* g_autofill_popup_proxy_node_ax_node = nullptr; |
| 130 |
| 131 void DeleteAutofillPopupProxy() { |
| 132 if (g_autofill_popup_proxy_node) { |
| 133 g_autofill_popup_proxy_node->Destroy(); |
| 134 delete g_autofill_popup_proxy_node_ax_node; |
| 135 g_autofill_popup_proxy_node = nullptr; |
| 136 } |
| 137 } |
| 138 |
120 } // anonymous namespace | 139 } // anonymous namespace |
121 | 140 |
122 namespace aria_strings { | 141 namespace aria_strings { |
123 const char kAriaLivePolite[] = "polite"; | 142 const char kAriaLivePolite[] = "polite"; |
124 const char kAriaLiveAssertive[] = "assertive"; | 143 const char kAriaLiveAssertive[] = "assertive"; |
125 } | 144 } |
126 | 145 |
127 // static | 146 // static |
128 BrowserAccessibilityManager* BrowserAccessibilityManager::Create( | 147 BrowserAccessibilityManager* BrowserAccessibilityManager::Create( |
129 const ui::AXTreeUpdate& initial_tree, | 148 const ui::AXTreeUpdate& initial_tree, |
(...skipping 18 matching lines...) Expand all Loading... |
148 Initialize(initial_tree); | 167 Initialize(initial_tree); |
149 SetContentViewCore(content_view_core); | 168 SetContentViewCore(content_view_core); |
150 } | 169 } |
151 | 170 |
152 BrowserAccessibilityManagerAndroid::~BrowserAccessibilityManagerAndroid() { | 171 BrowserAccessibilityManagerAndroid::~BrowserAccessibilityManagerAndroid() { |
153 JNIEnv* env = AttachCurrentThread(); | 172 JNIEnv* env = AttachCurrentThread(); |
154 ScopedJavaLocalRef<jobject> obj = GetJavaRefFromRootManager(); | 173 ScopedJavaLocalRef<jobject> obj = GetJavaRefFromRootManager(); |
155 if (obj.is_null()) | 174 if (obj.is_null()) |
156 return; | 175 return; |
157 | 176 |
| 177 // Clean up autofill popup proxy node in case the popup was not dismissed. |
| 178 DeleteAutofillPopupProxy(); |
| 179 |
158 Java_BrowserAccessibilityManager_onNativeObjectDestroyed( | 180 Java_BrowserAccessibilityManager_onNativeObjectDestroyed( |
159 env, obj, reinterpret_cast<intptr_t>(this)); | 181 env, obj, reinterpret_cast<intptr_t>(this)); |
160 } | 182 } |
161 | 183 |
162 // static | 184 // static |
163 ui::AXTreeUpdate | 185 ui::AXTreeUpdate |
164 BrowserAccessibilityManagerAndroid::GetEmptyDocument() { | 186 BrowserAccessibilityManagerAndroid::GetEmptyDocument() { |
165 ui::AXNodeData empty_document; | 187 ui::AXNodeData empty_document; |
166 empty_document.id = 0; | 188 empty_document.id = 0; |
167 empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA; | 189 empty_document.role = ui::AX_ROLE_ROOT_WEB_AREA; |
(...skipping 568 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
736 env, obj, android_node->unique_id()); | 758 env, obj, android_node->unique_id()); |
737 } | 759 } |
738 } | 760 } |
739 | 761 |
740 jint BrowserAccessibilityManagerAndroid::FindElementType( | 762 jint BrowserAccessibilityManagerAndroid::FindElementType( |
741 JNIEnv* env, | 763 JNIEnv* env, |
742 const JavaParamRef<jobject>& obj, | 764 const JavaParamRef<jobject>& obj, |
743 jint start_id, | 765 jint start_id, |
744 const JavaParamRef<jstring>& element_type_str, | 766 const JavaParamRef<jstring>& element_type_str, |
745 jboolean forwards) { | 767 jboolean forwards) { |
| 768 // Navigate forwards to the autofill popup's proxy node if focus is currently |
| 769 // on the element hosting the autofill popup. Once within the popup, a back |
| 770 // press will navigate back to the element hosting the popup. |
| 771 if (forwards && start_id == g_element_hosting_autofill_popup_unique_id && |
| 772 g_autofill_popup_proxy_node) { |
| 773 return g_autofill_popup_proxy_node->unique_id(); |
| 774 } |
| 775 |
746 BrowserAccessibilityAndroid* start_node = GetFromUniqueID(start_id); | 776 BrowserAccessibilityAndroid* start_node = GetFromUniqueID(start_id); |
747 if (!start_node) | 777 if (!start_node) |
748 return 0; | 778 return 0; |
749 | 779 |
750 BrowserAccessibilityManager* root_manager = GetRootManager(); | 780 BrowserAccessibilityManager* root_manager = GetRootManager(); |
751 if (!root_manager) | 781 if (!root_manager) |
752 return 0; | 782 return 0; |
753 | 783 |
754 BrowserAccessibility* root = root_manager->GetRoot(); | 784 BrowserAccessibility* root = root_manager->GetRoot(); |
755 if (!root) | 785 if (!root) |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
911 } | 941 } |
912 | 942 |
913 return true; | 943 return true; |
914 } | 944 } |
915 | 945 |
916 void BrowserAccessibilityManagerAndroid::SetAccessibilityFocus( | 946 void BrowserAccessibilityManagerAndroid::SetAccessibilityFocus( |
917 JNIEnv* env, | 947 JNIEnv* env, |
918 const JavaParamRef<jobject>& obj, | 948 const JavaParamRef<jobject>& obj, |
919 jint id) { | 949 jint id) { |
920 BrowserAccessibilityAndroid* node = GetFromUniqueID(id); | 950 BrowserAccessibilityAndroid* node = GetFromUniqueID(id); |
921 if (!node) | 951 if (node) |
922 return; | 952 node->manager()->SetAccessibilityFocus(*node); |
923 | |
924 node->manager()->SetAccessibilityFocus(*node); | |
925 } | 953 } |
926 | 954 |
927 bool BrowserAccessibilityManagerAndroid::IsSlider( | 955 bool BrowserAccessibilityManagerAndroid::IsSlider( |
928 JNIEnv* env, | 956 JNIEnv* env, |
929 const JavaParamRef<jobject>& obj, | 957 const JavaParamRef<jobject>& obj, |
930 jint id) { | 958 jint id) { |
931 BrowserAccessibilityAndroid* node = GetFromUniqueID(id); | 959 BrowserAccessibilityAndroid* node = GetFromUniqueID(id); |
932 if (!node) | 960 if (!node) |
933 return false; | 961 return false; |
934 | 962 |
935 return node->GetRole() == ui::AX_ROLE_SLIDER; | 963 return node->GetRole() == ui::AX_ROLE_SLIDER; |
936 } | 964 } |
937 | 965 |
| 966 void BrowserAccessibilityManagerAndroid::OnAutofillPopupDisplayed( |
| 967 JNIEnv* env, |
| 968 const JavaParamRef<jobject>& obj) { |
| 969 if (!base::FeatureList::IsEnabled(features::kAndroidAutofillAccessibility)) |
| 970 return; |
| 971 |
| 972 BrowserAccessibility* current_focus = GetFocus(); |
| 973 if (current_focus == nullptr) { |
| 974 return; |
| 975 } |
| 976 |
| 977 DeleteAutofillPopupProxy(); |
| 978 |
| 979 g_autofill_popup_proxy_node = BrowserAccessibility::Create(); |
| 980 g_autofill_popup_proxy_node_ax_node = new ui::AXNode(nullptr, -1, -1); |
| 981 ui::AXNodeData ax_node_data; |
| 982 ax_node_data.role = ui::AX_ROLE_MENU; |
| 983 ax_node_data.SetName("Autofill"); |
| 984 ax_node_data.state = 1 << ui::AX_STATE_READ_ONLY; |
| 985 ax_node_data.state |= 1 << ui::AX_STATE_FOCUSABLE; |
| 986 ax_node_data.state |= 1 << ui::AX_STATE_SELECTABLE; |
| 987 g_autofill_popup_proxy_node_ax_node->SetData(ax_node_data); |
| 988 g_autofill_popup_proxy_node->Init(this, g_autofill_popup_proxy_node_ax_node); |
| 989 |
| 990 g_element_hosting_autofill_popup_unique_id = current_focus->unique_id(); |
| 991 } |
| 992 |
| 993 void BrowserAccessibilityManagerAndroid::OnAutofillPopupDismissed( |
| 994 JNIEnv* env, |
| 995 const JavaParamRef<jobject>& obj) { |
| 996 g_element_hosting_autofill_popup_unique_id = -1; |
| 997 DeleteAutofillPopupProxy(); |
| 998 } |
| 999 |
| 1000 jboolean BrowserAccessibilityManagerAndroid::IsAutofillPopupNode( |
| 1001 JNIEnv* env, |
| 1002 const JavaParamRef<jobject>& obj, |
| 1003 jint id) { |
| 1004 return g_autofill_popup_proxy_node && |
| 1005 g_autofill_popup_proxy_node->unique_id() == id; |
| 1006 } |
| 1007 |
938 bool BrowserAccessibilityManagerAndroid::Scroll( | 1008 bool BrowserAccessibilityManagerAndroid::Scroll( |
939 JNIEnv* env, | 1009 JNIEnv* env, |
940 const JavaParamRef<jobject>& obj, | 1010 const JavaParamRef<jobject>& obj, |
941 jint id, | 1011 jint id, |
942 int direction) { | 1012 int direction) { |
943 BrowserAccessibilityAndroid* node = GetFromUniqueID(id); | 1013 BrowserAccessibilityAndroid* node = GetFromUniqueID(id); |
944 if (!node) | 1014 if (!node) |
945 return false; | 1015 return false; |
946 | 1016 |
947 return node->Scroll(direction); | 1017 return node->Scroll(direction); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
986 | 1056 |
987 JNIEnv* env = AttachCurrentThread(); | 1057 JNIEnv* env = AttachCurrentThread(); |
988 return root_manager->java_ref().get(env); | 1058 return root_manager->java_ref().get(env); |
989 } | 1059 } |
990 | 1060 |
991 bool RegisterBrowserAccessibilityManager(JNIEnv* env) { | 1061 bool RegisterBrowserAccessibilityManager(JNIEnv* env) { |
992 return RegisterNativesImpl(env); | 1062 return RegisterNativesImpl(env); |
993 } | 1063 } |
994 | 1064 |
995 } // namespace content | 1065 } // namespace content |
OLD | NEW |