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_client.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 element_hosting_autofill_popup_id_ = -1; | |
dmazzoni
2017/03/28 16:47:35
I think globals like this are typically named some
csashi
2017/03/28 17:48:10
Done.
| |
125 | |
126 // The element that currently has focus. Will be used to set | |
127 // |element_hosting_autofill_popup_id_| when we display an autofill popup. | |
128 int32_t current_focused_id_ = -1; | |
dmazzoni
2017/03/28 16:47:35
You don't need to keep track of this. Just call Ge
| |
129 | |
130 // Autofill popup will not be part of the |AXTree| that is sent by renderer. | |
131 // Hence, we need a proxy |AXNode| to represent the autofill popup. | |
132 BrowserAccessibility* autofill_popup_proxy_node_ = nullptr; | |
133 ui::AXNode* autofill_popup_proxy_node_ax_node_ = nullptr; | |
134 | |
120 } // anonymous namespace | 135 } // anonymous namespace |
121 | 136 |
122 namespace aria_strings { | 137 namespace aria_strings { |
123 const char kAriaLivePolite[] = "polite"; | 138 const char kAriaLivePolite[] = "polite"; |
124 const char kAriaLiveAssertive[] = "assertive"; | 139 const char kAriaLiveAssertive[] = "assertive"; |
125 } | 140 } |
126 | 141 |
142 const base::Feature kAutofillAccessibility{"AndroidAutofillAccessibility", | |
143 base::FEATURE_DISABLED_BY_DEFAULT}; | |
144 | |
127 // static | 145 // static |
128 BrowserAccessibilityManager* BrowserAccessibilityManager::Create( | 146 BrowserAccessibilityManager* BrowserAccessibilityManager::Create( |
129 const ui::AXTreeUpdate& initial_tree, | 147 const ui::AXTreeUpdate& initial_tree, |
130 BrowserAccessibilityDelegate* delegate, | 148 BrowserAccessibilityDelegate* delegate, |
131 BrowserAccessibilityFactory* factory) { | 149 BrowserAccessibilityFactory* factory) { |
132 return new BrowserAccessibilityManagerAndroid( | 150 return new BrowserAccessibilityManagerAndroid( |
133 ScopedJavaLocalRef<jobject>(), initial_tree, delegate, factory); | 151 ScopedJavaLocalRef<jobject>(), initial_tree, delegate, factory); |
134 } | 152 } |
135 | 153 |
136 BrowserAccessibilityManagerAndroid* | 154 BrowserAccessibilityManagerAndroid* |
(...skipping 473 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
610 if (node) | 628 if (node) |
611 node->manager()->DoDefaultAction(*node); | 629 node->manager()->DoDefaultAction(*node); |
612 } | 630 } |
613 | 631 |
614 void BrowserAccessibilityManagerAndroid::Focus(JNIEnv* env, | 632 void BrowserAccessibilityManagerAndroid::Focus(JNIEnv* env, |
615 const JavaParamRef<jobject>& obj, | 633 const JavaParamRef<jobject>& obj, |
616 jint id) { | 634 jint id) { |
617 BrowserAccessibilityAndroid* node = GetFromUniqueID(id); | 635 BrowserAccessibilityAndroid* node = GetFromUniqueID(id); |
618 if (node) | 636 if (node) |
619 node->manager()->SetFocus(*node); | 637 node->manager()->SetFocus(*node); |
638 current_focused_id_ = id; | |
620 } | 639 } |
621 | 640 |
622 void BrowserAccessibilityManagerAndroid::Blur( | 641 void BrowserAccessibilityManagerAndroid::Blur( |
623 JNIEnv* env, | 642 JNIEnv* env, |
624 const JavaParamRef<jobject>& obj) { | 643 const JavaParamRef<jobject>& obj) { |
625 SetFocus(*GetRoot()); | 644 SetFocus(*GetRoot()); |
626 } | 645 } |
627 | 646 |
628 void BrowserAccessibilityManagerAndroid::ScrollToMakeNodeVisible( | 647 void BrowserAccessibilityManagerAndroid::ScrollToMakeNodeVisible( |
629 JNIEnv* env, | 648 JNIEnv* env, |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
736 env, obj, android_node->unique_id()); | 755 env, obj, android_node->unique_id()); |
737 } | 756 } |
738 } | 757 } |
739 | 758 |
740 jint BrowserAccessibilityManagerAndroid::FindElementType( | 759 jint BrowserAccessibilityManagerAndroid::FindElementType( |
741 JNIEnv* env, | 760 JNIEnv* env, |
742 const JavaParamRef<jobject>& obj, | 761 const JavaParamRef<jobject>& obj, |
743 jint start_id, | 762 jint start_id, |
744 const JavaParamRef<jstring>& element_type_str, | 763 const JavaParamRef<jstring>& element_type_str, |
745 jboolean forwards) { | 764 jboolean forwards) { |
765 // Navigate forwards to the autofill popup's proxy node if focus is currently | |
766 // on the element hosting the autofill popup. Once within the popup, a back | |
767 // press will navigate back to the element hosting the popup. | |
768 if (forwards && start_id == element_hosting_autofill_popup_id_ && | |
769 autofill_popup_proxy_node_) { | |
770 return autofill_popup_proxy_node_->unique_id(); | |
771 } | |
772 | |
746 BrowserAccessibilityAndroid* start_node = GetFromUniqueID(start_id); | 773 BrowserAccessibilityAndroid* start_node = GetFromUniqueID(start_id); |
747 if (!start_node) | 774 if (!start_node) |
748 return 0; | 775 return 0; |
749 | 776 |
750 BrowserAccessibilityManager* root_manager = GetRootManager(); | 777 BrowserAccessibilityManager* root_manager = GetRootManager(); |
751 if (!root_manager) | 778 if (!root_manager) |
752 return 0; | 779 return 0; |
753 | 780 |
754 BrowserAccessibility* root = root_manager->GetRoot(); | 781 BrowserAccessibility* root = root_manager->GetRoot(); |
755 if (!root) | 782 if (!root) |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
911 } | 938 } |
912 | 939 |
913 return true; | 940 return true; |
914 } | 941 } |
915 | 942 |
916 void BrowserAccessibilityManagerAndroid::SetAccessibilityFocus( | 943 void BrowserAccessibilityManagerAndroid::SetAccessibilityFocus( |
917 JNIEnv* env, | 944 JNIEnv* env, |
918 const JavaParamRef<jobject>& obj, | 945 const JavaParamRef<jobject>& obj, |
919 jint id) { | 946 jint id) { |
920 BrowserAccessibilityAndroid* node = GetFromUniqueID(id); | 947 BrowserAccessibilityAndroid* node = GetFromUniqueID(id); |
921 if (!node) | 948 if (node) |
922 return; | 949 node->manager()->SetAccessibilityFocus(*node); |
923 | |
924 node->manager()->SetAccessibilityFocus(*node); | |
925 } | 950 } |
926 | 951 |
927 bool BrowserAccessibilityManagerAndroid::IsSlider( | 952 bool BrowserAccessibilityManagerAndroid::IsSlider( |
928 JNIEnv* env, | 953 JNIEnv* env, |
929 const JavaParamRef<jobject>& obj, | 954 const JavaParamRef<jobject>& obj, |
930 jint id) { | 955 jint id) { |
931 BrowserAccessibilityAndroid* node = GetFromUniqueID(id); | 956 BrowserAccessibilityAndroid* node = GetFromUniqueID(id); |
932 if (!node) | 957 if (!node) |
933 return false; | 958 return false; |
934 | 959 |
935 return node->GetRole() == ui::AX_ROLE_SLIDER; | 960 return node->GetRole() == ui::AX_ROLE_SLIDER; |
936 } | 961 } |
937 | 962 |
963 void BrowserAccessibilityManagerAndroid::OnAutofillPopupDisplayed( | |
964 JNIEnv* env, | |
965 const JavaParamRef<jobject>& obj) { | |
966 if (!base::FeatureList::IsEnabled(kAutofillAccessibility)) | |
967 return; | |
968 | |
969 if (autofill_popup_proxy_node_) { | |
970 LOG(ERROR) << "AutofillPopup proxy node exists, unique_id=" | |
dmazzoni
2017/03/28 16:47:35
Remove this debugging
csashi
2017/03/28 17:48:10
Done.
| |
971 << autofill_popup_proxy_node_->unique_id(); | |
972 OnAutofillPopupDismissed(env, obj); | |
973 } | |
974 | |
975 autofill_popup_proxy_node_ = BrowserAccessibility::Create(); | |
dmazzoni
2017/03/28 16:47:35
Do we need a check that this doesn't already exist
csashi
2017/03/28 17:48:10
The if statement above checks that.
| |
976 autofill_popup_proxy_node_ax_node_ = new ui::AXNode(nullptr, -1, -1); | |
977 ui::AXNodeData ax_node_data; | |
978 ax_node_data.role = ui::AX_ROLE_MENU; | |
979 content::ContentClient* content_client = content::GetContentClient(); | |
980 ax_node_data.SetName(content_client->GetLocalizedString( | |
981 IDS_AX_AUTOFILL_POPUP_ACCESSIBLE_NODE_DATA)); | |
982 ax_node_data.state = 1 << ui::AX_STATE_READ_ONLY; | |
983 ax_node_data.state |= 1 << ui::AX_STATE_FOCUSABLE; | |
984 ax_node_data.state |= 1 << ui::AX_STATE_SELECTABLE; | |
985 autofill_popup_proxy_node_ax_node_->SetData(ax_node_data); | |
986 autofill_popup_proxy_node_->Init(this, autofill_popup_proxy_node_ax_node_); | |
987 | |
988 element_hosting_autofill_popup_id_ = current_focused_id_; | |
dmazzoni
2017/03/28 16:47:35
Use GetFocus()->GetId() here
csashi
2017/03/28 17:48:10
Done.
| |
989 } | |
990 | |
991 void BrowserAccessibilityManagerAndroid::OnAutofillPopupDismissed( | |
992 JNIEnv* env, | |
993 const JavaParamRef<jobject>& obj) { | |
994 element_hosting_autofill_popup_id_ = -1; | |
995 | |
996 if (autofill_popup_proxy_node_) { | |
dmazzoni
2017/03/28 16:47:35
Do we also need to clean this up if
BrowserAccessi
csashi
2017/03/28 17:48:10
Done.
| |
997 autofill_popup_proxy_node_->Destroy(); | |
998 delete autofill_popup_proxy_node_ax_node_; | |
999 autofill_popup_proxy_node_ = nullptr; | |
1000 } | |
1001 } | |
1002 | |
1003 jboolean BrowserAccessibilityManagerAndroid::IsAutofillPopupNode( | |
1004 JNIEnv* env, | |
1005 const JavaParamRef<jobject>& obj, | |
1006 jint id) { | |
1007 return autofill_popup_proxy_node_ && | |
1008 autofill_popup_proxy_node_->unique_id() == id; | |
1009 } | |
1010 | |
1011 jint BrowserAccessibilityManagerAndroid::GetElementHostingAutofillPopupId( | |
1012 JNIEnv* env, | |
1013 const base::android::JavaParamRef<jobject>& obj) { | |
1014 return autofill_popup_proxy_node_ ? autofill_popup_proxy_node_->unique_id() | |
1015 : -1; | |
1016 } | |
1017 | |
938 bool BrowserAccessibilityManagerAndroid::Scroll( | 1018 bool BrowserAccessibilityManagerAndroid::Scroll( |
939 JNIEnv* env, | 1019 JNIEnv* env, |
940 const JavaParamRef<jobject>& obj, | 1020 const JavaParamRef<jobject>& obj, |
941 jint id, | 1021 jint id, |
942 int direction) { | 1022 int direction) { |
943 BrowserAccessibilityAndroid* node = GetFromUniqueID(id); | 1023 BrowserAccessibilityAndroid* node = GetFromUniqueID(id); |
944 if (!node) | 1024 if (!node) |
945 return false; | 1025 return false; |
946 | 1026 |
947 return node->Scroll(direction); | 1027 return node->Scroll(direction); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
986 | 1066 |
987 JNIEnv* env = AttachCurrentThread(); | 1067 JNIEnv* env = AttachCurrentThread(); |
988 return root_manager->java_ref().get(env); | 1068 return root_manager->java_ref().get(env); |
989 } | 1069 } |
990 | 1070 |
991 bool RegisterBrowserAccessibilityManager(JNIEnv* env) { | 1071 bool RegisterBrowserAccessibilityManager(JNIEnv* env) { |
992 return RegisterNativesImpl(env); | 1072 return RegisterNativesImpl(env); |
993 } | 1073 } |
994 | 1074 |
995 } // namespace content | 1075 } // namespace content |
OLD | NEW |